From nobody Sun Feb 8 14:56:30 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 4D71B30C347; Thu, 29 Jan 2026 15:28:04 +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=1769700485; cv=none; b=QPFCSGVZDckFMmscM9QFe63tlco+pHhQqz6KfrY+uvO+raacz3bph7KKVTtwuxzQyDGAN/hUz7w7457dYdZp3WQS5fEG/8K8aVEUSQeg/ShPGQ/FP/NxYY+DPnUZebcZt7tZ0piK+iLGNAPs0ew/V9b+9apxHQ2J2qqCXbNb0Qk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769700485; c=relaxed/simple; bh=EfEhAZia1vvxywCloQoiAeq3Iv5M1JcpChW5zrehlP8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=sAeoi/LhugdRA3lu2H2cu+9SJ8aKp/WHpRbTBJNF531eTT/PVD/Kgklzy3q6UNrybHFtvffn4tTfLSLaZ3A0JWC09o6RnrkB3fjidoayDH/wl+8CHDS/kQHO/QUq/55ncPJbHA8tJpk0Mi8UaOIH1s+JyKkDBYEglo6/Kic2YLA= 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=D7caN6U1; 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="D7caN6U1" Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 60TDonaZ009080; Thu, 29 Jan 2026 10:27:50 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h= content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=zNmZ1 ZToVHhVLeI4vZq2SGdxsSD9Eb7+F+YyKsv0tSM=; b=D7caN6U1GVC+mHOWJQgCN l4C/+xF1PNh3NtmiFLtVarxo0YSjEUtJgDD/YsxaX919df9/T1SH6Xn+s7NyqjO5 y6nYB+ux4971i8wU82nZ7HeFKBJJfa1eYkt4ul67JuBNNmjRgJy+2f+BiwR9xuu8 BgWB7boH9o3McPNyiC+Y1NwEnoYS8nySbLjzQV9LqfJd5bOXvd8EKa+Y3LbIRBwp YXAJcX790b6WImqYF9MLap4mJNwiQs4iSJGS8ZlIXuC2fobOUOrph9FwzbNWEOA8 /HF0g4bYAhxqBII1hHVb3VKZoWGnerHUW2mhaYerMxEUDOBu02bs3Kro0gLB1sSv A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4c08su8dd5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 29 Jan 2026 10:27:49 -0500 (EST) 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 60TFRmOG042239 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 29 Jan 2026 10:27:48 -0500 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, 29 Jan 2026 10:27:48 -0500 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) 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, 29 Jan 2026 10:27:48 -0500 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 29 Jan 2026 10:27:48 -0500 Received: from HYB-b1tGeUj4GP1.ad.analog.com (HYB-b1tGeUj4GP1.ad.analog.com [10.48.65.247]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 60TFRX1j002992; Thu, 29 Jan 2026 10:27:42 -0500 From: Antoniu Miclaus To: Lars-Peter Clausen , Michael Hennerich , Antoniu Miclaus , Jonathan Cameron , David Lechner , =?UTF-8?q?Nuno=20S=C3=A1?= , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , , , Subject: [PATCH 1/2] dt-bindings: iio: adc: ad4080: add AD4880 support Date: Thu, 29 Jan 2026 17:27:29 +0200 Message-ID: <20260129152731.154368-2-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260129152731.154368-1-antoniu.miclaus@analog.com> References: <20260129152731.154368-1-antoniu.miclaus@analog.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-ORIG-GUID: rA9L361kNp5tKGAWpI98Qj3vLYy3tzOO X-Proofpoint-GUID: rA9L361kNp5tKGAWpI98Qj3vLYy3tzOO X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI5MDEwNyBTYWx0ZWRfX4TfbJdt5QYT1 ICoY2xTSBHcfqt+5bqCTKadVzasfbLWG/Y3xwykIK43xFu6OkdBP5mt24iHeu0EAosZClDcFt85 AG7GEu9gjSbJntOVqSHtdDE0CCF76db7qV2H0W7WtyiGWLRjQ4I/Ejfi9anY39GesgO3rsN0f8d v5XcokThr9bqJN+VItP+uT1BigqR5QrOcsjO9E8vknf6uizcXZHVBk0j2vJ0f9RryeGP4/FclFP HGXAe/5rj/5xH6mJChcJ+3zXuM1DTU2knJqcm3c2p480gFAU/Xslv03upJY/dum02G/tr7Sg0P3 M2Se+PDN8agLQiEl8Wj+xdL/9r9R13N7a+IBCVFncsScZA8H5eqbUYUwfckv9lEF+FJ6GW1Zc6S /siA83PM8HEA21f9RGs/YOXw5LgVl8iNoTDKuBTvj+TZ47WksYdJbetTCWJ7jK9kZyDbhiLf+2i ckygecJ1yc4p0YHAgcA== X-Authority-Analysis: v=2.4 cv=IsgTsb/g c=1 sm=1 tr=0 ts=697b7c76 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=gAnH3GRIAAAA:8 a=UQpGX_erbYJYhkMay1IA:9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-29_02,2026-01-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 bulkscore=0 spamscore=0 adultscore=0 impostorscore=0 phishscore=0 clxscore=1015 malwarescore=0 suspectscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2601290107 Content-Type: text/plain; charset="utf-8" Add AD4880 dual-channel ADC to the AD4080 bindings. The AD4880 is a dual-channel variant with two independent ADC channels, each with its own SPI configuration interface. For AD4880, the binding requires: - adi,aux-spi-cs property for secondary channel chip select - Two io-backends entries for each channel's data interface Signed-off-by: Antoniu Miclaus --- .../bindings/iio/adc/adi,ad4080.yaml | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml b/Do= cumentation/devicetree/bindings/iio/adc/adi,ad4080.yaml index ccd6a0ac1539..3909e3095507 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml @@ -18,6 +18,9 @@ description: | service a wide variety of precision, wide bandwidth data acquisition applications. =20 + The AD4880 is a dual-channel variant with two independent ADC channels, + each with its own SPI configuration interface. + https://www.analog.com/media/en/technical-documentation/data-sheets/ad40= 80.pdf =20 $ref: /schemas/spi/spi-peripheral-props.yaml# @@ -31,10 +34,18 @@ properties: - adi,ad4084 - adi,ad4086 - adi,ad4087 + - adi,ad4880 =20 reg: maxItems: 1 =20 + adi,aux-spi-cs: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Chip select for the auxiliary SPI interface used by multi-channel + devices like AD4880. Each additional channel beyond the first requir= es + its own SPI configuration interface on a separate chip select. + spi-max-frequency: description: Configuration of the SPI bus. maximum: 50000000 @@ -57,7 +68,8 @@ properties: vrefin-supply: true =20 io-backends: - maxItems: 1 + minItems: 1 + maxItems: 2 =20 adi,lvds-cnv-enable: description: Enable the LVDS signal type on the CNV pin. Default is CM= OS. @@ -78,6 +90,23 @@ required: - vdd33-supply - vrefin-supply =20 +allOf: + - if: + properties: + compatible: + contains: + const: adi,ad4880 + then: + properties: + io-backends: + minItems: 2 + required: + - adi,aux-spi-cs + else: + properties: + io-backends: + maxItems: 1 + additionalProperties: false =20 examples: @@ -98,4 +127,22 @@ examples: io-backends =3D <&iio_backend>; }; }; + - | + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + adc@0 { + compatible =3D "adi,ad4880"; + reg =3D <0>; + adi,aux-spi-cs =3D <1>; + spi-max-frequency =3D <10000000>; + vdd33-supply =3D <&vdd33>; + vddldo-supply =3D <&vddldo>; + vrefin-supply =3D <&vrefin>; + clocks =3D <&cnv>; + clock-names =3D "cnv"; + io-backends =3D <&iio_backend_cha>, <&iio_backend_chb>; + }; + }; ... --=20 2.43.0 From nobody Sun Feb 8 14:56:30 2026 Received: from mx0b-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A66B832B9A0; Thu, 29 Jan 2026 15:28:07 +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=1769700489; cv=none; b=CS5JjOdHneMEePAnglKsiYU0h8l4OrDsjIOFyMVsoDd7waKNppukRmFCNCNeDRSP/txzGcBhXBb5m3kwS4xWjj+w7Vup9dk8sEulE+CBV884E82n8vTCUkI8yPsRaLisk8MRaVEyPgzVLa10rqcrnqkp2RnbK7sQO56qTYMs29I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769700489; c=relaxed/simple; bh=9Q2PDmAWK7okqFpBBIfoLfRndPHUH97jc50thp73IQk=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rwYBCjwQwwzQ9OVvMYB6Jx6CxNH/FMZcZxYBKu9qFqEbiOTxT4MEFoed9CYmf1M8XjydepuWASA8tEtQiCb30GGV5IBqf91jZI1y7AIVsCjgL3HpjtJViEkgCeCPfHf/CVLzvd+M5DqMCDsoUvUa0vFL9V4LEcBHx0Il+1uABsE= 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=AVvLIrXI; 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="AVvLIrXI" Received: from pps.filterd (m0375855.ppops.net [127.0.0.1]) by mx0b-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 60TBkq7X3783249; Thu, 29 Jan 2026 10:27:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h= content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=FXpvk e7eS0H7l3Ec1M2hpKBnE1wbXj9+7NDJ+EeQsyE=; b=AVvLIrXItfN3ah19qpDWl FDOgLUeoyoXBUC0GvBOUvlF7EPBR2NeGFCVX0kuINlg7PCQuaRhJwugyTtz1/I4R UqisD2vySUUQOuMdr/xQ0707AerOeRLPAI6FcLYoYqKR88G5+wKnCMkXGMG1baNX OE8Wr1dnMS9TqGSeluyOXxKogWLv1hHzNkqBfEmo0ig0/Ug9lXWWjLl5LQobJw0c G9XGoxOBApA1+0e/UQUyK6PKs0n8pv/IjrEeU6BoEe4Lfbq20JdXfbMTl4vcvScE ibbDq8Hog5vWn9DQB32LfkC5s2sq71+yzVxG47G2nl+6tbQQ983JeyCltaBSQd7l Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 4c011bj41k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 29 Jan 2026 10:27:52 -0500 (EST) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 60TFRpN0042249 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 29 Jan 2026 10:27:51 -0500 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 29 Jan 2026 10:27:51 -0500 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) 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, 29 Jan 2026 10:27:50 -0500 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 29 Jan 2026 10:27:50 -0500 Received: from HYB-b1tGeUj4GP1.ad.analog.com (HYB-b1tGeUj4GP1.ad.analog.com [10.48.65.247]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 60TFRX1k002992; Thu, 29 Jan 2026 10:27:44 -0500 From: Antoniu Miclaus To: Antoniu Miclaus , Lars-Peter Clausen , Michael Hennerich , "Jonathan Cameron" , David Lechner , =?UTF-8?q?Nuno=20S=C3=A1?= , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , , , Subject: [PATCH 2/2] iio: adc: ad4080: add support for AD4880 dual-channel ADC Date: Thu, 29 Jan 2026 17:27:30 +0200 Message-ID: <20260129152731.154368-3-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260129152731.154368-1-antoniu.miclaus@analog.com> References: <20260129152731.154368-1-antoniu.miclaus@analog.com> 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=PvmergM3 c=1 sm=1 tr=0 ts=697b7c78 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=gAnH3GRIAAAA:8 a=1TNaxu5aMze5YuMPDZ4A:9 X-Proofpoint-GUID: kzRqUpgAqpg7tFj65VXJ_vDA-XYBgSah X-Proofpoint-ORIG-GUID: kzRqUpgAqpg7tFj65VXJ_vDA-XYBgSah X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI5MDEwNyBTYWx0ZWRfXxOIr1xinhObj 3zP1p+P+gBUtocwTQUYtgOHtpvASwD1K6lsqLA7Tha48416gOrDPNzh3bnRBW1TWhtirQa3duBf mxRfRZng+WLypks1yuSZaAOhVZ8k1lFhUrMn1Rulyvqkb4y9oZvtIzwcbmEV7wF+n2MFDDqAhHJ avDI9Ah9NRQmzh/FHiX2uAtScVuwyPMGGafeCAfMWpwpir6v6SmqNT6EdULpPyzOXd5SQI8yX6s L4EN5IX0+08wIB01tRrri5KYs9jeznej0gxSHxnQOVT3EJJXYF0/x9DTr3zgIZlBUE0JA+xCDtc M3v7y1eG88ksVEK2ois4K6dvVILJsIpEgyih3N/oGk7jTY963RlnLpXLPzWwR1BDjlx4JVORpJF gfd2slLK8OB56XKh1/S2FZ2LkuuT1zRtGtOBPvVqiKCsKhGvnCS7xmQP7W456Kjzz8UhbR3V2C+ fHeSbc/ID+pRbX+oj8Q== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-29_02,2026-01-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 bulkscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 malwarescore=0 impostorscore=0 phishscore=0 adultscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2601290107 Content-Type: text/plain; charset="utf-8" Add support for the AD4880, a dual-channel 20-bit 40MSPS SAR ADC with integrated fully differential amplifiers (FDA). The AD4880 has two independent ADC channels, each with its own SPI configuration interface. The driver uses spi_new_ancillary_device() to create an additional SPI device for the second channel, allowing both channels to share the same SPI bus with different chip selects. Key changes: - Add AD4880 chip info with 2 channels - Extend state structure to support arrays of regmaps and backends - Refactor setup into per-channel function - Add adi,aux-spi-cs property for secondary channel chip select - Add channel index parameter to channel macro for scan_index support - Make all IIO attributes per-channel (filter_type, oversampling_ratio, sampling_frequency) for independent channel configuration Signed-off-by: Antoniu Miclaus --- drivers/iio/adc/ad4080.c | 236 ++++++++++++++++++++++++++++----------- 1 file changed, 172 insertions(+), 64 deletions(-) diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 7cf3b6ed7940..e588ff23a7a5 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,9 @@ #define AD4084_CHIP_ID 0x0054 #define AD4086_CHIP_ID 0x0056 #define AD4087_CHIP_ID 0x0057 +#define AD4880_CHIP_ID 0x0750 + +#define AD4080_MAX_CHANNELS 2 =20 #define AD4080_LVDS_CNV_CLK_CNT_MAX 7 =20 @@ -176,8 +180,9 @@ struct ad4080_chip_info { }; =20 struct ad4080_state { - struct regmap *regmap; - struct iio_backend *back; + struct spi_device *spi[AD4080_MAX_CHANNELS]; + struct regmap *regmap[AD4080_MAX_CHANNELS]; + struct iio_backend *back[AD4080_MAX_CHANNELS]; const struct ad4080_chip_info *info; /* * Synchronize access to members the of driver state, and ensure @@ -187,7 +192,7 @@ struct ad4080_state { unsigned int num_lanes; unsigned int dec_rate; unsigned long clk_rate; - enum ad4080_filter_type filter_type; + enum ad4080_filter_type filter_type[AD4080_MAX_CHANNELS]; bool lvds_cnv_en; }; =20 @@ -203,10 +208,11 @@ static int ad4080_reg_access(struct iio_dev *indio_de= v, unsigned int reg, { struct ad4080_state *st =3D iio_priv(indio_dev); =20 + /* Use channel 0 regmap for debugfs access */ if (readval) - return regmap_read(st->regmap, reg, readval); + return regmap_read(st->regmap[0], reg, readval); =20 - return regmap_write(st->regmap, reg, writeval); + return regmap_write(st->regmap[0], reg, writeval); } =20 static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2) @@ -227,8 +233,9 @@ static unsigned int ad4080_get_dec_rate(struct iio_dev = *dev, struct ad4080_state *st =3D iio_priv(dev); int ret; unsigned int data; + unsigned int ch =3D chan->channel; =20 - ret =3D regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data); + ret =3D regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data); if (ret) return ret; =20 @@ -240,13 +247,14 @@ static int ad4080_set_dec_rate(struct iio_dev *dev, unsigned int mode) { struct ad4080_state *st =3D iio_priv(dev); + unsigned int ch =3D chan->channel; =20 guard(mutex)(&st->lock); =20 - if ((st->filter_type >=3D SINC_5 && mode >=3D 512) || mode < 2) + if ((st->filter_type[ch] >=3D SINC_5 && mode >=3D 512) || mode < 2) return -EINVAL; =20 - return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG, + return regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG, AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, (ilog2(mode) - 1))); @@ -257,6 +265,7 @@ static int ad4080_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long m) { struct ad4080_state *st =3D iio_priv(indio_dev); + unsigned int ch =3D chan->channel; int dec_rate; =20 switch (m) { @@ -266,15 +275,15 @@ static int ad4080_read_raw(struct iio_dev *indio_dev, dec_rate =3D ad4080_get_dec_rate(indio_dev, chan); if (dec_rate < 0) return dec_rate; - if (st->filter_type =3D=3D SINC_5_COMP) + if (st->filter_type[ch] =3D=3D SINC_5_COMP) dec_rate *=3D 2; - if (st->filter_type) + if (st->filter_type[ch]) *val =3D DIV_ROUND_CLOSEST(st->clk_rate, dec_rate); else *val =3D st->clk_rate; return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (st->filter_type =3D=3D FILTER_NONE) { + if (st->filter_type[ch] =3D=3D FILTER_NONE) { *val =3D 1; } else { *val =3D ad4080_get_dec_rate(indio_dev, chan); @@ -292,10 +301,11 @@ static int ad4080_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct ad4080_state *st =3D iio_priv(indio_dev); + unsigned int ch =3D chan->channel; =20 switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (st->filter_type =3D=3D FILTER_NONE && val > 1) + if (st->filter_type[ch] =3D=3D FILTER_NONE && val > 1) return -EINVAL; =20 return ad4080_set_dec_rate(indio_dev, chan, val); @@ -304,23 +314,23 @@ static int ad4080_write_raw(struct iio_dev *indio_dev, } } =20 -static int ad4080_lvds_sync_write(struct ad4080_state *st) +static int ad4080_lvds_sync_write(struct ad4080_state *st, unsigned int ch) { - struct device *dev =3D regmap_get_device(st->regmap); + struct device *dev =3D regmap_get_device(st->regmap[ch]); int ret; =20 - ret =3D regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + ret =3D regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN); if (ret) return ret; =20 - ret =3D iio_backend_interface_data_align(st->back, 10000); + ret =3D iio_backend_interface_data_align(st->back[ch], 10000); if (ret) return dev_err_probe(dev, ret, "Data alignment process failed\n"); =20 dev_dbg(dev, "Success: Pattern correct and Locked!\n"); - return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + return regmap_clear_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_= A, AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN); } =20 @@ -329,9 +339,10 @@ static int ad4080_get_filter_type(struct iio_dev *dev, { struct ad4080_state *st =3D iio_priv(dev); unsigned int data; + unsigned int ch =3D chan->channel; int ret; =20 - ret =3D regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data); + ret =3D regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data); if (ret) return ret; =20 @@ -343,6 +354,7 @@ static int ad4080_set_filter_type(struct iio_dev *dev, unsigned int mode) { struct ad4080_state *st =3D iio_priv(dev); + unsigned int ch =3D chan->channel; int dec_rate; int ret; =20 @@ -355,18 +367,18 @@ static int ad4080_set_filter_type(struct iio_dev *dev, if (mode >=3D SINC_5 && dec_rate >=3D 512) return -EINVAL; =20 - ret =3D iio_backend_filter_type_set(st->back, mode); + ret =3D iio_backend_filter_type_set(st->back[ch], mode); if (ret) return ret; =20 - ret =3D regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG, + ret =3D regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG, AD4080_FILTER_CONFIG_FILTER_SEL_MSK, FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK, mode)); if (ret) return ret; =20 - st->filter_type =3D mode; + st->filter_type[ch] =3D mode; =20 return 0; } @@ -377,17 +389,18 @@ static int ad4080_read_avail(struct iio_dev *indio_de= v, long mask) { struct ad4080_state *st =3D iio_priv(indio_dev); + unsigned int ch =3D chan->channel; =20 switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - switch (st->filter_type) { + switch (st->filter_type[ch]) { case FILTER_NONE: *vals =3D ad4080_dec_rate_none; *length =3D ARRAY_SIZE(ad4080_dec_rate_none); break; default: *vals =3D ad4080_dec_rate_avail; - *length =3D st->filter_type >=3D SINC_5 ? + *length =3D st->filter_type[ch] >=3D SINC_5 ? (ARRAY_SIZE(ad4080_dec_rate_avail) - 2) : ARRAY_SIZE(ad4080_dec_rate_avail); break; @@ -399,11 +412,35 @@ static int ad4080_read_avail(struct iio_dev *indio_de= v, } } =20 +static int ad4080_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad4080_state *st =3D iio_priv(indio_dev); + unsigned int ch; + int ret; + + for (ch =3D 0; ch < st->info->num_channels; ch++) { + /* + * Each backend has a single channel (channel 0 from the + * backend's perspective), so always use channel index 0. + */ + if (test_bit(ch, scan_mask)) + ret =3D iio_backend_chan_enable(st->back[ch], 0); + else + ret =3D iio_backend_chan_disable(st->back[ch], 0); + if (ret) + return ret; + } + + return 0; +} + static const struct iio_info ad4080_iio_info =3D { .debugfs_reg_access =3D ad4080_reg_access, .read_raw =3D ad4080_read_raw, .write_raw =3D ad4080_write_raw, .read_avail =3D ad4080_read_avail, + .update_scan_mode =3D ad4080_update_scan_mode, }; =20 static const struct iio_enum ad4080_filter_type_enum =3D { @@ -414,23 +451,23 @@ static const struct iio_enum ad4080_filter_type_enum = =3D { }; =20 static struct iio_chan_spec_ext_info ad4080_ext_info[] =3D { - IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad4080_filter_type_enum), - IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, + IIO_ENUM("filter_type", IIO_SEPARATE, &ad4080_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE, &ad4080_filter_type_enum), { } }; =20 -#define AD4080_CHANNEL_DEFINE(bits, storage) { \ +#define AD4080_CHANNEL_DEFINE(bits, storage, idx) { \ .type =3D IIO_VOLTAGE, \ .indexed =3D 1, \ - .channel =3D 0, \ - .info_mask_separate =3D BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + .channel =3D (idx), \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - .info_mask_shared_by_all_available =3D \ + .info_mask_separate_available =3D \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .ext_info =3D ad4080_ext_info, \ - .scan_index =3D 0, \ + .scan_index =3D (idx), \ .scan_type =3D { \ .sign =3D 's', \ .realbits =3D (bits), \ @@ -438,17 +475,22 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[= ] =3D { }, \ } =20 -static const struct iio_chan_spec ad4080_channel =3D AD4080_CHANNEL_DEFINE= (20, 32); +static const struct iio_chan_spec ad4080_channel =3D AD4080_CHANNEL_DEFINE= (20, 32, 0); + +static const struct iio_chan_spec ad4081_channel =3D AD4080_CHANNEL_DEFINE= (20, 32, 0); =20 -static const struct iio_chan_spec ad4081_channel =3D AD4080_CHANNEL_DEFINE= (20, 32); +static const struct iio_chan_spec ad4083_channel =3D AD4080_CHANNEL_DEFINE= (16, 16, 0); =20 -static const struct iio_chan_spec ad4083_channel =3D AD4080_CHANNEL_DEFINE= (16, 16); +static const struct iio_chan_spec ad4084_channel =3D AD4080_CHANNEL_DEFINE= (16, 16, 0); =20 -static const struct iio_chan_spec ad4084_channel =3D AD4080_CHANNEL_DEFINE= (16, 16); +static const struct iio_chan_spec ad4086_channel =3D AD4080_CHANNEL_DEFINE= (14, 16, 0); =20 -static const struct iio_chan_spec ad4086_channel =3D AD4080_CHANNEL_DEFINE= (14, 16); +static const struct iio_chan_spec ad4087_channel =3D AD4080_CHANNEL_DEFINE= (14, 16, 0); =20 -static const struct iio_chan_spec ad4087_channel =3D AD4080_CHANNEL_DEFINE= (14, 16); +static const struct iio_chan_spec ad4880_channels[] =3D { + AD4080_CHANNEL_DEFINE(20, 32, 0), + AD4080_CHANNEL_DEFINE(20, 32, 1), +}; =20 static const struct ad4080_chip_info ad4080_chip_info =3D { .name =3D "ad4080", @@ -510,25 +552,34 @@ static const struct ad4080_chip_info ad4087_chip_info= =3D { .lvds_cnv_clk_cnt_max =3D 1, }; =20 -static int ad4080_setup(struct iio_dev *indio_dev) +static const struct ad4080_chip_info ad4880_chip_info =3D { + .name =3D "ad4880", + .product_id =3D AD4880_CHIP_ID, + .scale_table =3D ad4080_scale_table, + .num_scales =3D ARRAY_SIZE(ad4080_scale_table), + .num_channels =3D 2, + .channels =3D ad4880_channels, + .lvds_cnv_clk_cnt_max =3D AD4080_LVDS_CNV_CLK_CNT_MAX, +}; + +static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch) { - struct ad4080_state *st =3D iio_priv(indio_dev); - struct device *dev =3D regmap_get_device(st->regmap); + struct device *dev =3D regmap_get_device(st->regmap[ch]); __le16 id_le; u16 id; int ret; =20 - ret =3D regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, + ret =3D regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A, AD4080_INTERFACE_CONFIG_A_SW_RESET); if (ret) return ret; =20 - ret =3D regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, + ret =3D regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A, AD4080_INTERFACE_CONFIG_A_SDO_ENABLE); if (ret) return ret; =20 - ret =3D regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le, + ret =3D regmap_bulk_read(st->regmap[ch], AD4080_REG_PRODUCT_ID_L, &id_le, sizeof(id_le)); if (ret) return ret; @@ -537,18 +588,18 @@ static int ad4080_setup(struct iio_dev *indio_dev) if (id !=3D st->info->product_id) dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id); =20 - ret =3D regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A, + ret =3D regmap_set_bits(st->regmap[ch], AD4080_REG_GPIO_CONFIG_A, AD4080_GPIO_CONFIG_A_GPO_1_EN); if (ret) return ret; =20 - ret =3D regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B, + ret =3D regmap_write(st->regmap[ch], AD4080_REG_GPIO_CONFIG_B, FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK, AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY)); if (ret) return ret; =20 - ret =3D iio_backend_num_lanes_set(st->back, st->num_lanes); + ret =3D iio_backend_num_lanes_set(st->back[ch], st->num_lanes); if (ret) return ret; =20 @@ -556,7 +607,7 @@ static int ad4080_setup(struct iio_dev *indio_dev) return 0; =20 /* Set maximum LVDS Data Transfer Latency */ - ret =3D regmap_update_bits(st->regmap, + ret =3D regmap_update_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_B, AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK, FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK, @@ -565,24 +616,39 @@ static int ad4080_setup(struct iio_dev *indio_dev) return ret; =20 if (st->num_lanes > 1) { - ret =3D regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + ret =3D regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_= A, AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES); if (ret) return ret; } =20 - ret =3D regmap_set_bits(st->regmap, + ret =3D regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_B, AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN); if (ret) return ret; =20 - return ad4080_lvds_sync_write(st); + return ad4080_lvds_sync_write(st, ch); +} + +static int ad4080_setup(struct iio_dev *indio_dev) +{ + struct ad4080_state *st =3D iio_priv(indio_dev); + unsigned int ch; + int ret; + + for (ch =3D 0; ch < st->info->num_channels; ch++) { + ret =3D ad4080_setup_channel(st, ch); + if (ret) + return ret; + } + + return 0; } =20 static int ad4080_properties_parse(struct ad4080_state *st) { - struct device *dev =3D regmap_get_device(st->regmap); + struct device *dev =3D regmap_get_device(st->regmap[0]); =20 st->lvds_cnv_en =3D device_property_read_bool(dev, "adi,lvds-cnv-enable"); =20 @@ -596,12 +662,19 @@ static int ad4080_properties_parse(struct ad4080_stat= e *st) return 0; } =20 +static void ad4080_unregister_ancillary(void *data) +{ + spi_unregister_device(data); +} + static int ad4080_probe(struct spi_device *spi) { + static const char * const backend_names[] =3D { "0", "1" }; struct iio_dev *indio_dev; struct device *dev =3D &spi->dev; struct ad4080_state *st; struct clk *clk; + unsigned int ch; int ret; =20 indio_dev =3D devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -610,6 +683,10 @@ static int ad4080_probe(struct spi_device *spi) =20 st =3D iio_priv(indio_dev); =20 + st->info =3D spi_get_device_match_data(spi); + if (!st->info) + return -ENODEV; + ret =3D devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4080_power_supplies), ad4080_power_supplies); @@ -617,13 +694,35 @@ static int ad4080_probe(struct spi_device *spi) return dev_err_probe(dev, ret, "failed to get and enable supplies\n"); =20 - st->regmap =3D devm_regmap_init_spi(spi, &ad4080_regmap_config); - if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + /* Setup primary SPI device (channel 0) */ + st->spi[0] =3D spi; + st->regmap[0] =3D devm_regmap_init_spi(spi, &ad4080_regmap_config); + if (IS_ERR(st->regmap[0])) + return PTR_ERR(st->regmap[0]); =20 - st->info =3D spi_get_device_match_data(spi); - if (!st->info) - return -ENODEV; + /* Setup ancillary SPI device for additional channel (AD4880) */ + if (st->info->num_channels > 1) { + u32 aux_cs; + + ret =3D device_property_read_u32(dev, "adi,aux-spi-cs", &aux_cs); + if (ret) + return dev_err_probe(dev, ret, + "missing adi,aux-spi-cs for multi-channel device\n"); + + st->spi[1] =3D spi_new_ancillary_device(spi, aux_cs); + if (IS_ERR(st->spi[1])) + return PTR_ERR(st->spi[1]); + + ret =3D devm_add_action_or_reset(dev, ad4080_unregister_ancillary, + st->spi[1]); + if (ret) + return ret; + + st->regmap[1] =3D devm_regmap_init_spi(st->spi[1], + &ad4080_regmap_config); + if (IS_ERR(st->regmap[1])) + return PTR_ERR(st->regmap[1]); + } =20 ret =3D devm_mutex_init(dev, &st->lock); if (ret) @@ -644,15 +743,22 @@ static int ad4080_probe(struct spi_device *spi) =20 st->clk_rate =3D clk_get_rate(clk); =20 - st->back =3D devm_iio_backend_get(dev, NULL); - if (IS_ERR(st->back)) - return PTR_ERR(st->back); + /* Get backends for all channels */ + for (ch =3D 0; ch < st->info->num_channels; ch++) { + if (st->info->num_channels > 1) + st->back[ch] =3D devm_iio_backend_get(dev, backend_names[ch]); + else + st->back[ch] =3D devm_iio_backend_get(dev, NULL); =20 - ret =3D devm_iio_backend_request_buffer(dev, st->back, indio_dev); - if (ret) - return ret; + if (IS_ERR(st->back[ch])) + return PTR_ERR(st->back[ch]); + + ret =3D devm_iio_backend_enable(dev, st->back[ch]); + if (ret) + return ret; + } =20 - ret =3D devm_iio_backend_enable(dev, st->back); + ret =3D devm_iio_backend_request_buffer(dev, st->back[0], indio_dev); if (ret) return ret; =20 @@ -670,6 +776,7 @@ static const struct spi_device_id ad4080_id[] =3D { { "ad4084", (kernel_ulong_t)&ad4084_chip_info }, { "ad4086", (kernel_ulong_t)&ad4086_chip_info }, { "ad4087", (kernel_ulong_t)&ad4087_chip_info }, + { "ad4880", (kernel_ulong_t)&ad4880_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4080_id); @@ -681,6 +788,7 @@ static const struct of_device_id ad4080_of_match[] =3D { { .compatible =3D "adi,ad4084", &ad4084_chip_info }, { .compatible =3D "adi,ad4086", &ad4086_chip_info }, { .compatible =3D "adi,ad4087", &ad4087_chip_info }, + { .compatible =3D "adi,ad4880", &ad4880_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4080_of_match); --=20 2.43.0