From nobody Fri Sep 25 19:19:17 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 2199543B6F3; Wed, 9 Sep 2026 08:28:17 +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=1788942499; cv=none; b=MQB1k0yZ4WBMn2ookFfJpu7ODEkqeUb449df4mSiHK9yhOHVqrhGnGAS+Rbbnn5/uU4T2Dh8VQgAq8bcy6eMCkbCXjtOTvrzCZYeIN7ks2pZneYvoikpksZW84d6lqohcTDPAg99jH2JK6Sf6FO3DgvwZMgxmXU3QpGI6wiJbw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788942499; c=relaxed/simple; bh=mChYRR+anAJlV/XXuQipsoPloSLDBwv8qUBlE0Gi/Nk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QdMOgJwrIht6nFxlMDO5Nhi7QDOmCk7CnfNwqQWfg0dXkRzw1BaVWeR42Rt+IYViTwUkYsBEpMB7el5fjNRN2wDO0Pm0F3AO5VGSm2i4vquzKcj2A023zt/P2g7+QOBE/RjMJH1W9NE/DLSdW/Jx8xRJadZSJ2zsU8GwiLGkPKI= 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=Y6DtSupA; 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="Y6DtSupA" 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 6894kJSn4155563; Wed, 9 Sep 2026 04:28:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=QMMK2 AvZDwPGu0wApDLh+EKw5oHyxtkZRvufSirdjQ0=; b=Y6DtSupAGe3sOYA4V6XLh rkIeL3KoUfb0dyvTApsnidRNdrd3i94RsYW6nBr0+adJdvauWSmO9V3vqYdmOvh7 fq1y2H0idGsj94QlpZDeB0L1Qcb5WlpY0d58i521/OwnNaM1fcFo2HEi12ArsAal jNWPHcXiqUVnuhnH3u78XG9ryArTR5IISW4qOeggGuGMesKy6RPK+dJa99cy+k20 0b0/Imgzxgd+AeneGqywryRkwpCzVytU/x1HVreJmEgEzSsf1na9VMUWRDs6nX1S xUKonec5vUFFsdLUFKzyjr2g0lnbOebFKnKLe9SyhjeQtvfPlPd21MyB2O65nakD g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4gjvfb1w5v-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 09 Sep 2026 04:28:13 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 6898SCEb001421 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 9 Sep 2026 04:28:12 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBMBX8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Wed, 9 Sep 2026 04:28:12 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Wed, 9 Sep 2026 04:28:12 -0400 Received: from HYB-li3PrmDPxTz.ad.analog.com (HYB-li3PrmDPxTz.ad.analog.com [10.48.65.171]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 6898RxF6032752; Wed, 9 Sep 2026 04:28:08 -0400 From: Andrei Stancovici To: =?UTF-8?q?Nuno=20S=C3=A1?= , Michael Hennerich , Jonathan Cameron , David Lechner , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Beguin , , , , CC: Andrei Stancovici Subject: [PATCH v4 1/3] dt-bindings: iio: adc: lltc,ltc2497: add LTC2499 to title Date: Wed, 9 Sep 2026 11:27:50 +0300 Message-ID: <20260909082755.366269-2-andrei.stancovici@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260909082755.366269-1-andrei.stancovici@analog.com> References: <20260909082755.366269-1-andrei.stancovici@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-GUID: 380qMVIWpooTzPMUWWv2MgMzkVPyORo5 X-Authority-Analysis: v=2.4 cv=Yvk/gYYX c=1 sm=1 tr=0 ts=6aa1189d cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=uXIjobp8t2wMuQ0fPvqm:22 a=gEfo2CItAAAA:8 a=VwQbUJbxAAAA:8 a=gAnH3GRIAAAA:8 a=EP9JJrKyo648RTWUWkgA:9 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwOTA5MDA5MiBTYWx0ZWRfX1LqCGTg7ELvb am5vZvd0vX6nNl48NkPwHw5wm6LLqADCJSMblGI2DMZ2bAlMrQalbJjb2a/6mBKNSMwKGIlGJIG BziIg7Nk6ZN0AYSNo/WxXzIld64z39w+EQOx2EEwXOmujW+1qJ/S X-Proofpoint-ORIG-GUID: 380qMVIWpooTzPMUWWv2MgMzkVPyORo5 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTA5MDA5MiBTYWx0ZWRfXxwdq+r+XPM2q 4tj1IObwnlnN/NbQ26r8gEC7iqhUR7dFUHosn7qPVTINr069SaeKV1PT9djkcWalRnb/4i66YMB p42EIWNKV+NymCGw+NhcwPiugh/LpwN5nxftVo5Yw4eRhqyvo0oxTWF07pZBLF3Ih47h2fnPzrl 52wEsm1mtRU3+P4AGW4qxghTvrziah25GSvjlCXTDJ8hEphoNs4NpKKM/E3b1r9G/0ZJWg4WRZY Xu2UPNDq8C7VGm7/YuXrNWJ+K2cntNci91t2MOJB+GuqA/x2xqeZFi6I2k+YPTAoUz00izBhnNW D4ju9DEhULFxfbUCY6sVC18J9guoGXG5iwdl4t3AdM3ylYaH4CGzu4k5fj1788GEla0DKsVmVzo KeD+oZ3fYgsNgzaHk+BVw/2cRRW+3Suyu3H2/NMqQwNh7VdvHpIFO60ZFCO/Yh4cnq8FEo7CuNX dF6Dran9a5AbkOM7TVA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-08_03,2026-09-08_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 bulkscore=0 adultscore=0 impostorscore=0 suspectscore=0 clxscore=1015 phishscore=0 priorityscore=1501 malwarescore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2609090092 Content-Type: text/plain; charset="utf-8" The LTC2499 is already listed in the compatible enum and covered by the description, but was missing from the binding title. Add it so the title matches the set of devices the schema documents. No schema or property change is needed. Acked-by: Rob Herring (Arm) Signed-off-by: Andrei Stancovici --- Changes in v4: - No change. Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml b/= Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml index c884b6e03767..8aa1ba0a8728 100644 --- a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml +++ b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/adc/lltc,ltc2497.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# =20 -title: Linear Technology / Analog Devices LTC2497 and LTC2309 ADC +title: Linear Technology / Analog Devices LTC2497, LTC2499 and LTC2309 ADC =20 maintainers: - Michael Hennerich --=20 2.43.0 From nobody Fri Sep 25 19:19:17 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 A0D594582F9; Wed, 9 Sep 2026 08:28:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788942507; cv=none; b=bm8/eikjO1O+38ZFHXvCNi5LWISiCFbjn5jxxP72NI6bEkSyoa99ZQVL9Tup2Udcosxn9RFHOV90s3Ze5lcxVQNw9HK7H80FthnSflTK6bkrnE1fZTm1pp0Eun3X7H4TDOVfA0K9e1qlK0s7n2OR3IrMqZqGzX1HUAQBFrbSJzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788942507; c=relaxed/simple; bh=i7WpoL1qVtGjoFhBgpzCjOdL+pfVTEsfstRk7nzMVac=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HIPqOmHs5lsmoTBNh4dIP8G9CVh7aTtjwu+ayfD8p2KOtviEslOD5DrFE9r1hNWRbTqq3ODw6g9Ov/w16Fz/cbrLiCJ5VvTlF8UbztLyQ1t9LryssGsJ/0mZ5YK4SGwGa+WRmfKBvXxTLvRKDnI4jha1FO2QJFxADaSgqKvxqiI= 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=Z0nlKANw; 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="Z0nlKANw" 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 6897kRoE2763506; Wed, 9 Sep 2026 04:28:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=xULnj SEHord/eXvQP6+P7gu71y6kWTY81ENNfhcxJa0=; b=Z0nlKANwCSWIazslVVObl eB59GAqavoJM9Bzen+WHOAkhIZzwvkDuj4nv4k9cn3Y1DhTajNK8yuGMGEnmMW6E mw3UKB17/E7DopyeM2EYn3kq1GEP/9dCmIY0Ll+8D9qM90E+RtI3qDt3xjUU/Smg rcgG4FFa0EuwWIlaXO6Ml1CbR3CmchIS498mzjyft4COfHTF5gnV/pGDevBjqR8e cG2mVpvZhWsBBMWB5qnwEtLkTS1bjEqFyXCYk/Imh0aos+bTY3NHzJ1Cz0RDjH/k JBpnEvXy/RJd/uDAQbs0tt280aZZthuRLYw9FJp0oaezXbLIhJGuJCKF/KyG3B15 Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 4gh1dc6309-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 09 Sep 2026 04:28:19 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 6898SIoe001436 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 9 Sep 2026 04:28:18 -0400 Received: from ASHBCASHYB4.ad.analog.com (10.64.17.132) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Wed, 9 Sep 2026 04:28:18 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBCASHYB4.ad.analog.com (10.64.17.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Wed, 9 Sep 2026 04:28:17 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Wed, 9 Sep 2026 04:28:17 -0400 Received: from HYB-li3PrmDPxTz.ad.analog.com (HYB-li3PrmDPxTz.ad.analog.com [10.48.65.171]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 6898RxF7032752; Wed, 9 Sep 2026 04:28:10 -0400 From: Andrei Stancovici To: =?UTF-8?q?Nuno=20S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Liam Beguin , , , , CC: Andrei Stancovici , Andy Shevchenko Subject: [PATCH v4 2/3] iio: adc: ltc2497: add LTC2499 internal temperature channel Date: Wed, 9 Sep 2026 11:27:51 +0300 Message-ID: <20260909082755.366269-3-andrei.stancovici@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260909082755.366269-1-andrei.stancovici@analog.com> References: <20260909082755.366269-1-andrei.stancovici@analog.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Authority-Analysis: v=2.4 cv=XOsAjwhE c=1 sm=1 tr=0 ts=6aa118a3 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=N--XFCr6TIEc_64PeIT2:22 a=gAnH3GRIAAAA:8 a=QyXUC8HyAAAA:8 a=oH3iYeRb2tCmVxh1MEoA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-Spam-Info: AW1haW4tMjYwOTA5MDA5MiBTYWx0ZWRfX70G8SsQgBqXX rTDdit4RRAqhTWk99GycktZWNWzg2uznBVVc1aBZAZctUy2wWA3U9A9Zhkmc110JiJA44Inklnm x4Wgk9pVeQLGFJC6at/7zy4l5bJksPVa83ik/7gl+65m86H5rhmQ X-Proofpoint-ORIG-GUID: gwca-IOP1Lv6ZaxpRTZxwIObHhuDCt_j X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTA5MDA5MiBTYWx0ZWRfX1OoNj6sTmsko B3UxXlSFUsJ4yyXJVVVxhIT1zBN7GTIuh4nyQmc2qarJE3I38aSjwBPFe1fo1YrcAnbe5+BT7Ey p8rZJr+ZXi2C9XH2i2/YgPclqwKbC6jjKMPT+9aIBWkELPdJKCzpkz/CmDRfYmrVE3MVrnMyKkc H/Rz79LhWzMyn99v26r07OgZdyUsv58yuYbFI0a4Ui1RM33KYOv9NdAwfZ6hxVY1b81nyc6KaD3 7JP9oR2TlgCz5Rkn4Tsb1BX8B21ZyDfsmUxuAY14rq9KJkQ0O1J6zMSD85Gc53/MiBZldVCb8RH e3LgP63xc0ptT/g2fx/hlIWltP+J3QuQ8E2FfwLFvC03F0nNgpKoQPy+6fA+j3lV74vd+CiugXm W4s8ZEvmxJQdhRT5E8YfJQaSIOj8sCfuWcDuusAo35c4D/omqSq6/l9rnAaaSpvVS7JriZpyBka dLHNQmxJ9m4/xfZG43w== X-Proofpoint-GUID: gwca-IOP1Lv6ZaxpRTZxwIObHhuDCt_j X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-08_03,2026-09-08_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 lowpriorityscore=0 clxscore=1011 priorityscore=1501 malwarescore=0 bulkscore=0 phishscore=0 impostorscore=0 adultscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2609090092 The LTC2499 includes an internal temperature sensor. Expose it as an IIO_TEMP channel with raw, scale and offset. Scale and offset are derived from the reference voltage, so reading them returns an error if firmware does not describe a vref-supply. As this is a new feature on a part that already works without it, failing probe is not an option. Selecting the sensor needs a second command byte, and the part keeps the configuration it last latched unless that byte is sent again. Voltage reads on this part therefore also send the second byte. Datasheet: https://www.analog.com/media/en/technical-documentation/data-she= ets/2499fe.pdf Reviewed-by: Andy Shevchenko Signed-off-by: Andrei Stancovici --- Changes in v4: - Description cut down to what a reader needs: the sensor, the ABI it exposes and the vref dependency. The PTAT derivation and the num_channels detail are gone; the maths stays as comments next to the code that does it. - struct ltc2497_chip_info: booleans moved last, as requested, with one deviation I should flag - I hoisted `name` to the front rather than only shifting the flags down. pahole, LP64, all three instances: as posted (flags after resolution) 16 B, 2 B hole, 48 B flags moved last, as requested 24 B, 4 B hole + 6 B tail, 72 B name, resolution, flags last (v4) 16 B, no hole, 48 B The pre-series struct already had a 4-byte hole after `resolution` and the flags fell into it, which is why the posted version did not grow. Moving them to the end leaves that hole and adds tail padding. Hoisting the pointer puts the flags last as asked and removes the hole. On ILP32 all three orderings are 12 B. If you would rather have the literal reorder, say so and I will take the 24 B. - Why the second command byte is sent on every conversion rather than only when the latched configuration already differs: simplicity. It costs one extra byte per conversion, and a conversion takes 150 ms, so tracking the latched state to avoid it does not pay for itself. The code comment now records that the unconditional send is deliberate; the rationale itself is here rather than in the commit message. - Added the Datasheet: trailer. - Andy's Reviewed-by is kept. The only code change in this patch since v3 is the member reorder he asked for, plus one sentence of comment. drivers/iio/adc/ltc2497-core.c | 58 +++++++++++++++++++++++++++++++--- drivers/iio/adc/ltc2497.c | 36 +++++++++++++++++++++ drivers/iio/adc/ltc2497.h | 14 +++++++- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c index 2dc5c7044269..6df9c72bd8cf 100644 --- a/drivers/iio/adc/ltc2497-core.c +++ b/drivers/iio/adc/ltc2497-core.c @@ -9,9 +9,11 @@ #include #include #include +#include #include #include #include +#include =20 #include "ltc2497.h" =20 @@ -95,10 +97,45 @@ static int ltc2497core_read_raw(struct iio_dev *indio_d= ev, if (ret < 0) return ret; =20 - *val =3D ret / 1000; - *val2 =3D ddata->chip_info->resolution + 1; + switch (chan->type) { + case IIO_TEMP: + /* + * raw is normalised to 2^(resolution + 1), i.e. + * raw =3D 2 * DATAOUT24, so the PTAT scale (datasheet + * Vref / 1570 per Kelvin) doubles its denominator and, + * in m=C2=B0C, becomes Vref_uV / 3140000. + */ + *val =3D ret; + *val2 =3D 3140000; + return IIO_VAL_FRACTIONAL; + case IIO_VOLTAGE: + *val =3D ret / (MICRO / MILLI); + *val2 =3D ddata->chip_info->resolution + 1; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } =20 - return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + ret =3D regulator_get_voltage(ddata->ref); + if (ret < 0) + return ret; + if (ret =3D=3D 0) + return -EINVAL; + /* + * 0 =C2=B0C =3D=3D 273.15 K must map to raw + offset such that + * (raw + offset) * scale =3D=3D 0 m=C2=B0C, i.e. + * offset =3D -273150 / scale + * =3D -273150 * 3140000 / Vref_uV + * Computed in 64-bit to avoid overflow. + */ + *val =3D div_s64(ABSOLUTE_ZERO_MILLICELSIUS * 3140000LL, ret); + return IIO_VAL_INT; + default: + return -EINVAL; + } =20 default: return -EINVAL; @@ -126,6 +163,14 @@ static int ltc2497core_read_raw(struct iio_dev *indio_= dev, .differential =3D 1, \ } =20 +#define LTC2497_TEMP_CHANNEL { \ + .type =3D IIO_TEMP, \ + .address =3D LTC2497_TEMP_ADDR, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ +} + static const struct iio_chan_spec ltc2497core_channel[] =3D { LTC2497_CHAN(0, LTC2497_SGL, "CH0"), LTC2497_CHAN(1, LTC2497_SGL, "CH1"), @@ -159,6 +204,7 @@ static const struct iio_chan_spec ltc2497core_channel[]= =3D { LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN), LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN), LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN), + LTC2497_TEMP_CHANNEL, }; =20 static const struct iio_info ltc2497core_info =3D { @@ -183,7 +229,11 @@ int ltc2497core_probe(struct device *dev, struct iio_d= ev *indio_dev) indio_dev->info =3D <c2497core_info; indio_dev->modes =3D INDIO_DIRECT_MODE; indio_dev->channels =3D ltc2497core_channel; - indio_dev->num_channels =3D ARRAY_SIZE(ltc2497core_channel); + /* Only the ltc2499 has a temperature channel; it is the last entry. */ + if (ddata->chip_info->has_temp) + indio_dev->num_channels =3D ARRAY_SIZE(ltc2497core_channel); + else + indio_dev->num_channels =3D ARRAY_SIZE(ltc2497core_channel) - 1; =20 ret =3D ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL); if (ret < 0) diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index c1668b5a351e..ea55b417213a 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -84,6 +84,41 @@ static int ltc2497_result_and_measure(struct ltc2497core= _driverdata *ddata, return 0; } =20 + /* + * Parts with the internal PTAT sensor (LTC2499) latch their converter + * configuration via a second command byte and only re-evaluate it when + * that byte has EN2 set; a single byte, or a second byte with EN2 =3D 0, + * means "keep previous". A one-byte channel select therefore cannot pull + * the device back out of temperature mode, so a voltage read after a + * temperature read would keep returning the PTAT result. Always drive t= he + * second byte with EN2 set on these parts: IM =3D 1 for a temperature re= ad, + * EN2 alone (IM =3D 0) to (re)select an external input. FA =3D FB =3D 0= keeps + * the power-on simultaneous 50/60Hz rejection, whose worst-case + * conversion time the driver's wait already covers. + * + * The byte could be skipped while the latched configuration is already + * the one wanted; it is sent on every conversion for simplicity. + */ + if (ddata->chip_info->has_temp) { + u8 cmd[2]; + + if (address =3D=3D LTC2497_TEMP_ADDR) { + cmd[0] =3D LTC2497_ENABLE | LTC2497_CONFIG_DEFAULT; + cmd[1] =3D LTC2499_EN2 | LTC2499_IM; + } else { + cmd[0] =3D LTC2497_ENABLE | address; + cmd[1] =3D LTC2499_EN2; + } + + ret =3D i2c_master_send(st->client, cmd, sizeof(cmd)); + if (ret < 0) { + dev_err(&st->client->dev, "i2c transfer failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + return 0; + } + ret =3D i2c_smbus_write_byte(st->client, LTC2497_ENABLE | address); if (ret) @@ -137,6 +172,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = =3D { [TYPE_LTC2499] =3D { .resolution =3D 24, .name =3D "ltc2499", + .has_temp =3D true, }, }; =20 diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h index 64e81c95a3dd..2b797fd19651 100644 --- a/drivers/iio/adc/ltc2497.h +++ b/drivers/iio/adc/ltc2497.h @@ -4,9 +4,21 @@ #define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE #define LTC2497_CONVERSION_TIME_MS 150ULL =20 +/* + * Sentinel passed as `address` to result_and_measure() to request a + * temperature conversion instead of a voltage channel. Valid channel + * addresses fit in 5 bits (0x00=E2=80=930x1F), so 0xFF is unambiguous. + */ +#define LTC2497_TEMP_ADDR 0xFF + +/* Second config-byte bits (LTC2499 / LTC2493 only) */ +#define LTC2499_EN2 BIT(7) /* enable second config byte */ +#define LTC2499_IM BIT(6) /* 1 =3D measure internal temp sensor */ + struct ltc2497_chip_info { - u32 resolution; const char *name; + u32 resolution; + bool has_temp; }; =20 struct ltc2497core_driverdata { --=20 2.43.0 From nobody Fri Sep 25 19:19:17 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 83D00455622; Wed, 9 Sep 2026 08:28:26 +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=1788942508; cv=none; b=kP9tL5s4Oi4MtEXpy9tsqDOVtsHUiZFbuv3dW8oX2K4L6Z3SxHXOsCOyGI5f9HD1gju8bF4thkyVP5Bvd9hxWxKhuuWPrRclQO0+Bk+T6SpEDmD626SbNw3xF0Z0IjOP1nR9VFmiURJnd9baIRswFOJWLiXxh4+AafAR5HuJW48= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788942508; c=relaxed/simple; bh=A44j0GA22AUbtWPElv5ZndciXH6u8cj3zOC1mYRHrMA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eBuGsOz+Rj7Vx6MYCACwTr68oIEvdsJrfWmPgf2pdTspk0YfdEVEHuVFTJSVhWTSLvPVjS8iIIsUNgjWojwa6zsZMsOtMCVlBtlz71YcSpl6cHd8ur0tH4gbaX9Dcv6MYJ35gSmB5ZkDHjw7Lsz7dg5Y8UOqRPMSPycJPp38Z+A= 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=GjX2YbdM; 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="GjX2YbdM" 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 6897wPXm2763878; Wed, 9 Sep 2026 04:28:21 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=PQkNQ U7zapyrvcToz/o5ddsZJyuAPXhUHM/vecUkA4o=; b=GjX2YbdMvudA3ARBjaFtY AWACvdNjhk/3q4hxmcYJA5WhiPzQe8+HTqIX7eaeEi2dEumlT/0nX7vKjU8xoQC1 h5NTItCQZpWLf9+n4p+5wh9ESFTvaGgurMdg2742wd5vvU+hM/rPbw9UzEWVpq7c zCHQW+cWOsIsU4Eqop7BtjTeUOgiS7fT6usTP+4cBub5dBJMt/JDvMw2VxSwPV+O f1fdbLVfKmZX/Sgp7MQW6EQ8HPEnyxgYanokeVacAtb/4Ta6kLMrJN7VIs/Ianet 4Hf4PxVBVzp6l66H+CtaVbwR3fOVMRG+fi4hGC+RwPvET4Ojc+ZUpV4O6z8zCVMQ g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 4gh1dc630c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 09 Sep 2026 04:28:21 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 6898SK8V001446 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 9 Sep 2026 04:28:20 -0400 Received: from ASHBCASHYB4.ad.analog.com (10.64.17.132) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Wed, 9 Sep 2026 04:28:20 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBCASHYB4.ad.analog.com (10.64.17.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Wed, 9 Sep 2026 04:28:20 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Wed, 9 Sep 2026 04:28:19 -0400 Received: from HYB-li3PrmDPxTz.ad.analog.com (HYB-li3PrmDPxTz.ad.analog.com [10.48.65.171]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 6898RxF8032752; Wed, 9 Sep 2026 04:28:13 -0400 From: Andrei Stancovici To: =?UTF-8?q?Nuno=20S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Liam Beguin , , , , CC: Andrei Stancovici Subject: [PATCH v4 3/3] iio: adc: ltc2497: add 2x conversion speed mode Date: Wed, 9 Sep 2026 11:27:52 +0300 Message-ID: <20260909082755.366269-4-andrei.stancovici@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260909082755.366269-1-andrei.stancovici@analog.com> References: <20260909082755.366269-1-andrei.stancovici@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=XOsAjwhE c=1 sm=1 tr=0 ts=6aa118a5 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=N--XFCr6TIEc_64PeIT2:22 a=gAnH3GRIAAAA:8 a=JFow1UHeAF9eE4mkUcAA:9 X-Proofpoint-Spam-Info: AW1haW4tMjYwOTA5MDA5MiBTYWx0ZWRfX7jLorGaIePVB 1NA185KR6BkWfgGWhYVst0TULnsHYIoK//JrRlkI5KUf9LpBxf2zZaYEZpxlaCLCh+6c50ifQJQ WMK2XXj3o4fLPkFdH367weUN/SJ5joDmqpk10t6t+cpYxDzNZNb9 X-Proofpoint-ORIG-GUID: -_HQDFmjrT8Ybdj1ToOPRf_m8Zgl_Eza X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTA5MDA5MiBTYWx0ZWRfX9dJJBVYX7Tu0 nuBxvVJ6ttme3SSjPqtIfsUpTjezPAhIafFFuVXjqJy7/X7SrMrhRuFNE/Tgj524eQBF35zkCV3 up0sdUoEtbidht2m10qeKdfBnsD48W5TqmI/SYe/go/nl7J/7yVJLvmYPrM8pkrTlJiuEO4hOcU A/vYdpWJFfuHWpN5/rP2IIJQM5G/fAG4hjVHK7uyUuHFZ2ErZvmbawmV5GF4t8P+BuJA86++AGA j0W/Niz4CZ5LPFoegEoaurkJse2+6UtJ26qR/7EVW5n4JWP05WzslVd75yQk8+KSugz3J3vQ7rr +Jx0aJ0FCo9R07QAevfAlNw1qkcnrkr+0EGc6u+q2H5zv8pQzx520nAQcWR/qdTFPJA5ee5FY7H 1Zh89jBF+ekE09ihnnzHfLhZCFAWMOtXQx1MKzA29L6ovoiQ1i6MJLtF7Ixd/qSqLIKWNiqQOMp FjKYq+aKlJQpcCN6Lzg== X-Proofpoint-GUID: -_HQDFmjrT8Ybdj1ToOPRf_m8Zgl_Eza X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-08_03,2026-09-08_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 lowpriorityscore=0 clxscore=1015 priorityscore=1501 malwarescore=0 bulkscore=0 phishscore=0 impostorscore=0 adultscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2609090092 Content-Type: text/plain; charset="utf-8" The LTC2499 can convert at twice the output rate by disabling the offset auto-calibration. Expose it through sampling_frequency and sampling_frequency_available on the voltage channels. The part ignores the setting while measuring temperature, so the temperature channel does not carry the attribute. The wait before a result is read is keyed on the conversion currently in flight, whose duration is fixed by the mode that was active when it started rather than by the mode just selected. Otherwise the first read after a 1x -> 2x switch can reprogram the part while a 1x conversion is still running, which the part NACKs. Datasheet: https://www.analog.com/media/en/technical-documentation/data-she= ets/2499fe.pdf Signed-off-by: Andrei Stancovici Reviewed-by: Andy Shevchenko --- Changes in v4: - The channel table is now two static const tables selected in probe, replacing the devm_kmemdup() copy and runtime fix-up of a shared table. The 32 voltage entries moved into a macro that emits the whole table (same shape as DEFINE_AD7380_2_CHANNEL); the move is mechanical and the entries are unchanged. Checked two ways: the preprocessor expansion of the non-speed table is identical to v3 apart from the added info_mask_shared_by_type_available =3D 0, and the sysfs attribute tree of both parts is byte-identical before and after. - Comments trimmed: the rounding rationale, the msleep granularity note and the FA/FB aside are gone; the paragraph explaining what 2x actually does is kept. - Naming settled on speed_2x / has_speed_mode throughout; the v3 mix of speed / sped / SPD is gone. - Description shortened. The in-flight conversion-time paragraph is kept because it is the part that is not obvious from the code. - struct ltc2497_chip_info reordered as described in patch 2/3. - Added the Datasheet: trailer. drivers/iio/adc/ltc2497-core.c | 242 ++++++++++++++++++++++++++------- drivers/iio/adc/ltc2497.c | 28 ++-- drivers/iio/adc/ltc2497.h | 17 ++- 3 files changed, 228 insertions(+), 59 deletions(-) diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c index 6df9c72bd8cf..fcf10e86da17 100644 --- a/drivers/iio/adc/ltc2497-core.c +++ b/drivers/iio/adc/ltc2497-core.c @@ -21,24 +21,54 @@ #define LTC2497_DIFF 0 #define LTC2497_SIGN BIT(3) =20 -static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata) +/* + * Output-rate modes, indexed by ltc2497core_driverdata.speed_2x + * (0 =3D 1x, the power-on default; 1 =3D 2x, LTC2499 only). The advertis= ed + * sampling_frequency and the conversion-time budget are two views of the = same + * mode, so they are kept in lock-step here. + */ +static const int ltc2497core_samp_freq_avail[] =3D { + 6, 800000, /* 1x: ~6.8 Hz (1 / t_CONV_1 typ 146.9ms) */ + 13, 600000, /* 2x: ~13.6 Hz (1 / t_CONV_2 typ 73.6ms) */ +}; + +static const unsigned int ltc2497core_conv_time_ms_tbl[] =3D { + LTC2497_CONV_TIME_1X_MS, /* 1x */ + LTC2499_CONV_TIME_2X_MS, /* 2x */ +}; + +static unsigned int ltc2497core_conv_time_ms(struct ltc2497core_driverdata= *ddata, + u8 address) +{ + /* + * SPD is ignored by the part during a temperature measurement: it + * always converts at 1x, so budget the 1x time regardless of the + * selected voltage-channel mode. + */ + if (address =3D=3D LTC2497_TEMP_ADDR) + return ltc2497core_conv_time_ms_tbl[0]; + + return ltc2497core_conv_time_ms_tbl[ddata->speed_2x]; +} + +static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata, + unsigned int conv_time_ms) { s64 time_elapsed; =20 time_elapsed =3D ktime_ms_delta(ktime_get(), ddata->time_prev); =20 - if (time_elapsed < LTC2497_CONVERSION_TIME_MS) { + if (time_elapsed < conv_time_ms) { /* delay if conversion time not passed * since last read or write */ - if (msleep_interruptible( - LTC2497_CONVERSION_TIME_MS - time_elapsed)) + if (msleep_interruptible(conv_time_ms - time_elapsed)) return -ERESTARTSYS; =20 return 0; } =20 - if (time_elapsed - LTC2497_CONVERSION_TIME_MS <=3D 0) { + if (time_elapsed - conv_time_ms <=3D 0) { /* We're in automatic mode - * so the last reading is still not outdated */ @@ -50,9 +80,18 @@ static int ltc2497core_wait_conv(struct ltc2497core_driv= erdata *ddata) =20 static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 addre= ss, int *val) { + unsigned int conv_time_ms =3D ltc2497core_conv_time_ms(ddata, address); int ret; =20 - ret =3D ltc2497core_wait_conv(ddata); + /* + * Wait for the conversion currently in flight, whose duration was fixed + * by the mode active when it was started (ddata->conv_time_prev). This + * can be longer than the freshly selected mode's time - e.g. a 1x + * conversion is still running when the first 2x read arrives after a + * sampling_frequency change - and reprogramming the device before it + * finishes would be NACKed (-EIO). + */ + ret =3D ltc2497core_wait_conv(ddata, ddata->conv_time_prev); if (ret < 0) return ret; =20 @@ -62,7 +101,17 @@ static int ltc2497core_read(struct ltc2497core_driverda= ta *ddata, u8 address, in return ret; ddata->addr_prev =3D address; =20 - if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS)) + /* + * The reprogram above starts a conversion in the new mode. + * Record its start time and duration before sleeping, so that if + * msleep_interruptible() is interrupted the conversion state is + * already consistent: the next retry then waits only the time + * remaining from the real start instead of from a stale + * time_prev, which would let it reprogram/read too early. + */ + ddata->time_prev =3D ktime_get(); + ddata->conv_time_prev =3D conv_time_ms; + if (msleep_interruptible(conv_time_ms)) return -ERESTARTSYS; } =20 @@ -71,6 +120,8 @@ static int ltc2497core_read(struct ltc2497core_driverdat= a *ddata, u8 address, in return ret; =20 ddata->time_prev =3D ktime_get(); + /* The read above auto-starts the next conversion in the current mode. */ + ddata->conv_time_prev =3D conv_time_ms; =20 return ret; } @@ -137,32 +188,113 @@ static int ltc2497core_read_raw(struct iio_dev *indi= o_dev, return -EINVAL; } =20 + case IIO_CHAN_INFO_SAMP_FREQ: + /* + * Only advertised on the voltage channels of parts with a speed + * mode; the sampling frequency is a property of the selected 1x/2x + * mode, not of an individual conversion. + */ + mutex_lock(&ddata->lock); + *val =3D ltc2497core_samp_freq_avail[ddata->speed_2x * 2]; + *val2 =3D ltc2497core_samp_freq_avail[ddata->speed_2x * 2 + 1]; + mutex_unlock(&ddata->lock); + + return IIO_VAL_INT_PLUS_MICRO; + default: return -EINVAL; } } =20 -#define LTC2497_CHAN(_chan, _addr, _ds_name) { \ +static int ltc2497core_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals =3D ltc2497core_samp_freq_avail; + *type =3D IIO_VAL_INT_PLUS_MICRO; + *length =3D ARRAY_SIZE(ltc2497core_samp_freq_avail); + return IIO_AVAIL_LIST; + + default: + return -EINVAL; + } +} + +static int ltc2497core_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ltc2497core_driverdata *ddata =3D iio_priv(indio_dev); + unsigned int i; + bool speed_2x; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + /* Match the (val, val2) pair against the advertised rates. */ + for (i =3D 0; i < ARRAY_SIZE(ltc2497core_samp_freq_avail); i +=3D 2) { + if (val =3D=3D ltc2497core_samp_freq_avail[i] && + val2 =3D=3D ltc2497core_samp_freq_avail[i + 1]) + break; + } + if (i =3D=3D ARRAY_SIZE(ltc2497core_samp_freq_avail)) + return -EINVAL; + + speed_2x =3D i / 2; + + mutex_lock(&ddata->lock); + ddata->speed_2x =3D speed_2x; + /* + * The new speed only takes effect once the second command byte + * is reprogrammed, so force the next read to reprogram rather + * than reuse the value already latched for this address. + * LTC2497_CONFIG_DEFAULT is not a valid channel/temperature + * address, so it is a safe re-arm sentinel (as used at probe). + * + * A conversion started under the old speed may still be in + * flight; its own duration (conv_time_prev), not the new mode's, + * still gates the next reprogram, so the timing state is left + * untouched here. + */ + ddata->addr_prev =3D LTC2497_CONFIG_DEFAULT; + mutex_unlock(&ddata->lock); + + return 0; + + default: + return -EINVAL; + } +} + +#define LTC2497_CHAN(_chan, _addr, _ds_name, _extra_mask) { \ .type =3D IIO_VOLTAGE, \ .indexed =3D 1, \ .channel =3D (_chan), \ .address =3D (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \ .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | (_extra_mask), \ + .info_mask_shared_by_type_available =3D (_extra_mask), \ .datasheet_name =3D (_ds_name), \ } =20 -#define LTC2497_CHAN_DIFF(_chan, _addr) { \ +#define LTC2497_CHAN_DIFF(_chan, _addr, _extra_mask) { \ .type =3D IIO_VOLTAGE, \ .indexed =3D 1, \ .channel =3D (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \ .channel2 =3D (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\ .address =3D (_addr | _chan), \ .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | (_extra_mask), \ + .info_mask_shared_by_type_available =3D (_extra_mask), \ .differential =3D 1, \ } =20 +/* + * SPD is ignored by the part during a temperature measurement, so the + * temperature channel carries no sampling-frequency attribute. + */ #define LTC2497_TEMP_CHANNEL { \ .type =3D IIO_TEMP, \ .address =3D LTC2497_TEMP_ADDR, \ @@ -171,44 +303,55 @@ static int ltc2497core_read_raw(struct iio_dev *indio= _dev, BIT(IIO_CHAN_INFO_OFFSET), \ } =20 -static const struct iio_chan_spec ltc2497core_channel[] =3D { - LTC2497_CHAN(0, LTC2497_SGL, "CH0"), - LTC2497_CHAN(1, LTC2497_SGL, "CH1"), - LTC2497_CHAN(2, LTC2497_SGL, "CH2"), - LTC2497_CHAN(3, LTC2497_SGL, "CH3"), - LTC2497_CHAN(4, LTC2497_SGL, "CH4"), - LTC2497_CHAN(5, LTC2497_SGL, "CH5"), - LTC2497_CHAN(6, LTC2497_SGL, "CH6"), - LTC2497_CHAN(7, LTC2497_SGL, "CH7"), - LTC2497_CHAN(8, LTC2497_SGL, "CH8"), - LTC2497_CHAN(9, LTC2497_SGL, "CH9"), - LTC2497_CHAN(10, LTC2497_SGL, "CH10"), - LTC2497_CHAN(11, LTC2497_SGL, "CH11"), - LTC2497_CHAN(12, LTC2497_SGL, "CH12"), - LTC2497_CHAN(13, LTC2497_SGL, "CH13"), - LTC2497_CHAN(14, LTC2497_SGL, "CH14"), - LTC2497_CHAN(15, LTC2497_SGL, "CH15"), - LTC2497_CHAN_DIFF(0, LTC2497_DIFF), - LTC2497_CHAN_DIFF(1, LTC2497_DIFF), - LTC2497_CHAN_DIFF(2, LTC2497_DIFF), - LTC2497_CHAN_DIFF(3, LTC2497_DIFF), - LTC2497_CHAN_DIFF(4, LTC2497_DIFF), - LTC2497_CHAN_DIFF(5, LTC2497_DIFF), - LTC2497_CHAN_DIFF(6, LTC2497_DIFF), - LTC2497_CHAN_DIFF(7, LTC2497_DIFF), - LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN), - LTC2497_TEMP_CHANNEL, -}; +/* + * Parts with a speed mode advertise sampling_frequency on their voltage + * channels; the two tables are otherwise identical. + */ +#define LTC2497_DEFINE_CHANNELS(_name, _extra_mask) \ +static const struct iio_chan_spec _name[] =3D { \ + LTC2497_CHAN(0, LTC2497_SGL, "CH0", _extra_mask), \ + LTC2497_CHAN(1, LTC2497_SGL, "CH1", _extra_mask), \ + LTC2497_CHAN(2, LTC2497_SGL, "CH2", _extra_mask), \ + LTC2497_CHAN(3, LTC2497_SGL, "CH3", _extra_mask), \ + LTC2497_CHAN(4, LTC2497_SGL, "CH4", _extra_mask), \ + LTC2497_CHAN(5, LTC2497_SGL, "CH5", _extra_mask), \ + LTC2497_CHAN(6, LTC2497_SGL, "CH6", _extra_mask), \ + LTC2497_CHAN(7, LTC2497_SGL, "CH7", _extra_mask), \ + LTC2497_CHAN(8, LTC2497_SGL, "CH8", _extra_mask), \ + LTC2497_CHAN(9, LTC2497_SGL, "CH9", _extra_mask), \ + LTC2497_CHAN(10, LTC2497_SGL, "CH10", _extra_mask), \ + LTC2497_CHAN(11, LTC2497_SGL, "CH11", _extra_mask), \ + LTC2497_CHAN(12, LTC2497_SGL, "CH12", _extra_mask), \ + LTC2497_CHAN(13, LTC2497_SGL, "CH13", _extra_mask), \ + LTC2497_CHAN(14, LTC2497_SGL, "CH14", _extra_mask), \ + LTC2497_CHAN(15, LTC2497_SGL, "CH15", _extra_mask), \ + LTC2497_CHAN_DIFF(0, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(1, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(2, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(3, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(4, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(5, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(6, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(7, LTC2497_DIFF, _extra_mask), \ + LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \ + LTC2497_TEMP_CHANNEL, \ +} + +LTC2497_DEFINE_CHANNELS(ltc2497core_channel, 0); +LTC2497_DEFINE_CHANNELS(ltc2497core_channel_samp_freq, + BIT(IIO_CHAN_INFO_SAMP_FREQ)); =20 static const struct iio_info ltc2497core_info =3D { .read_raw =3D ltc2497core_read_raw, + .read_avail =3D ltc2497core_read_avail, + .write_raw =3D ltc2497core_write_raw, }; =20 int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev) @@ -228,7 +371,10 @@ int ltc2497core_probe(struct device *dev, struct iio_d= ev *indio_dev) =20 indio_dev->info =3D <c2497core_info; indio_dev->modes =3D INDIO_DIRECT_MODE; - indio_dev->channels =3D ltc2497core_channel; + if (ddata->chip_info->has_speed_mode) + indio_dev->channels =3D ltc2497core_channel_samp_freq; + else + indio_dev->channels =3D ltc2497core_channel; /* Only the ltc2499 has a temperature channel; it is the last entry. */ if (ddata->chip_info->has_temp) indio_dev->num_channels =3D ARRAY_SIZE(ltc2497core_channel); @@ -259,6 +405,8 @@ int ltc2497core_probe(struct device *dev, struct iio_de= v *indio_dev) =20 ddata->addr_prev =3D LTC2497_CONFIG_DEFAULT; ddata->time_prev =3D ktime_get(); + /* Power-on default mode is 1x; a conversion is already in flight. */ + ddata->conv_time_prev =3D LTC2497_CONV_TIME_1X_MS; =20 mutex_init(&ddata->lock); =20 diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index ea55b417213a..15458d4e21a1 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -85,21 +85,24 @@ static int ltc2497_result_and_measure(struct ltc2497cor= e_driverdata *ddata, } =20 /* - * Parts with the internal PTAT sensor (LTC2499) latch their converter - * configuration via a second command byte and only re-evaluate it when - * that byte has EN2 set; a single byte, or a second byte with EN2 =3D 0, - * means "keep previous". A one-byte channel select therefore cannot pull - * the device back out of temperature mode, so a voltage read after a - * temperature read would keep returning the PTAT result. Always drive t= he - * second byte with EN2 set on these parts: IM =3D 1 for a temperature re= ad, - * EN2 alone (IM =3D 0) to (re)select an external input. FA =3D FB =3D 0= keeps - * the power-on simultaneous 50/60Hz rejection, whose worst-case - * conversion time the driver's wait already covers. + * Parts with a second config byte (LTC2499: internal PTAT sensor and/or + * the 2x speed mode) latch their converter configuration from that byte + * and only re-evaluate it when EN2 is set; a single byte, or a second + * byte with EN2 =3D 0, means "keep previous". A one-byte channel select + * therefore cannot pull the device back out of temperature mode, so a + * voltage read after a temperature read would keep returning the PTAT + * result. Always drive the second byte with EN2 set on these parts: + * - temperature read: IM =3D 1 (SPD is ignored by the part in + * temperature mode and is left 0 here); + * - voltage read: IM =3D 0 (external input), plus SPD when 2x is + * selected. + * FA =3D FB =3D 0 keeps the power-on simultaneous 50/60Hz rejection, who= se + * worst-case conversion time the driver's wait already covers. * * The byte could be skipped while the latched configuration is already * the one wanted; it is sent on every conversion for simplicity. */ - if (ddata->chip_info->has_temp) { + if (ddata->chip_info->has_temp || ddata->chip_info->has_speed_mode) { u8 cmd[2]; =20 if (address =3D=3D LTC2497_TEMP_ADDR) { @@ -108,6 +111,8 @@ static int ltc2497_result_and_measure(struct ltc2497cor= e_driverdata *ddata, } else { cmd[0] =3D LTC2497_ENABLE | address; cmd[1] =3D LTC2499_EN2; + if (ddata->speed_2x) + cmd[1] |=3D LTC2499_SPD; } =20 ret =3D i2c_master_send(st->client, cmd, sizeof(cmd)); @@ -173,6 +178,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = =3D { .resolution =3D 24, .name =3D "ltc2499", .has_temp =3D true, + .has_speed_mode =3D true, }, }; =20 diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h index 2b797fd19651..cee9a2f50b82 100644 --- a/drivers/iio/adc/ltc2497.h +++ b/drivers/iio/adc/ltc2497.h @@ -2,7 +2,17 @@ =20 #define LTC2497_ENABLE 0xA0 #define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE -#define LTC2497_CONVERSION_TIME_MS 150ULL + +/* + * Conversion-time bounds used to gate reads. Each value is the datasheet + * t_CONV maximum, rounded UP to the next whole millisecond. + * + * The 2x mode (LTC2499_SPD, LTC2499 only) disables the offset auto-calibr= ation + * to roughly double the output rate; adding the 2x wait time is what make= s the + * SPD control actually faster. + */ +#define LTC2497_CONV_TIME_1X_MS 150ULL /* ceil(t_CONV_1 simult. max 149.9= ) */ +#define LTC2499_CONV_TIME_2X_MS 76ULL /* ceil(t_CONV_2 simult. max 75.1)= */ =20 /* * Sentinel passed as `address` to result_and_measure() to request a @@ -14,11 +24,13 @@ /* Second config-byte bits (LTC2499 / LTC2493 only) */ #define LTC2499_EN2 BIT(7) /* enable second config byte */ #define LTC2499_IM BIT(6) /* 1 =3D measure internal temp sensor */ +#define LTC2499_SPD BIT(3) /* 1 =3D 2x output rate (offset cal off) */ =20 struct ltc2497_chip_info { const char *name; u32 resolution; bool has_temp; + bool has_speed_mode; /* SPD bit in the 2nd config byte (LTC2499/LTC2493) = */ }; =20 struct ltc2497core_driverdata { @@ -28,6 +40,9 @@ struct ltc2497core_driverdata { struct mutex lock; const struct ltc2497_chip_info *chip_info; u8 addr_prev; + bool speed_2x; /* SPD: false =3D 1x (default), true =3D 2x */ + /* Conversion time (ms) of the conversion currently in flight. */ + unsigned int conv_time_prev; int (*result_and_measure)(struct ltc2497core_driverdata *ddata, u8 address, int *val); }; --=20 2.43.0