From nobody Fri Oct 3 02:16:59 2025 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 8723F2E7BDE; Mon, 8 Sep 2025 07:36:15 +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=1757316977; cv=none; b=dN4dViEvg//nS1vLHMSktXkDUQ1GtS4mvr0sZW7vU3tS4qstQpw1SfFdQr8UarryNk71n1fBYaVLBLrlGnNfHS/79SHHr/gF4xpJTQmToRMCF6pw0FyjhX/zR2sHmJBvnzXYULTltNYjP1uxIB6ULyBkuDbQ1pgOOXaO+w/P46U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316977; c=relaxed/simple; bh=SWOMMJnqHYPK6Vqh6ctVMBuYoeTbaP1PK12sHnybwqE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RGRPYypZc0KNOXDC9KmoA9sucjnkQvaVWRdW9Ye2CdGnfncyQQzqSW1y7Per5Ey6JY2qYdwNHA9ebMQJHoLJ+Qa7Z/7EOAepLZpFYGJwOrOSmfIjjGyYxiej8JRE3R4Z2JEsRSRVk2C5oZ357yipdCX1hJOrfeiQ4DeMWQ8M+eY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none 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=DOt95Lvd; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none 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="DOt95Lvd" Received: from pps.filterd (m0375855.ppops.net [127.0.0.1]) by mx0b-00128a01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 588403RA005861; Mon, 8 Sep 2025 03:36:07 -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=NFjIx q+qwV5ssj6/hMukVubAke/jydqEL8Uwl1w/bWQ=; b=DOt95Lvd+zQWzn2ncnJaH XX14c2q99ImUhD8VHBNSIr9iSKEMBAzmXKgQrEQrSQcABaGs1NUnzW8OnfUn68mg WeTRKHvEy+EI3pS2ahyAMDxHUGzChhQWi+Fn3Ba81WeipW2rLZUiec/lpO1P40CA 3BlanZqZgvcNBIPxhgyKEBL78Xj1lhciQhYtk4xzoH3QC2Ligu03wNOE3lTpugDs OLXSdGTLhri5RoOHyWwQrkJDtwru9GvO28c+z9Hk/OmSpAkUyGZpFSESJcLUdtK7 L+T1lBVMs9mPIdXQ8zm9TD+AGQdM76x9SNaAcQbkfW6kg/f4QjG0ozaNiK64O/Hi w== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 491qqfgufg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 Sep 2025 03:36:06 -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 5887a5av036434 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 8 Sep 2025 03:36:05 -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.10; Mon, 8 Sep 2025 03:36:05 -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.10 via Frontend Transport; Mon, 8 Sep 2025 03:36:05 -0400 Received: from Ubuntu.ad.analog.com ([10.132.255.227]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 5887ZpEd004718; Mon, 8 Sep 2025 03:35:57 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus , David Lechner Subject: [PATCH v7 1/6] iio: add IIO_ALTCURRENT channel type Date: Mon, 8 Sep 2025 07:35:21 +0000 Message-ID: <20250908073531.3639-2-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908073531.3639-1-antoniu.miclaus@analog.com> References: <20250908073531.3639-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-Spam-Details-Enc: AW1haW4tMjUwOTA4MDAzNSBTYWx0ZWRfX5obTjZHe889q cIY4sqKTZJcKdY//NiT/EG4ML5aMw1jKlgXd6WZs9dVXosMYfxEiluwuMvltKhDfcgYb4jAwdjA Uv4m2c2D5tuLU6N9FaYiuCtHr+OI9teB7VW3lE7JjNPIH/CzJBfC7qwBWdUFT3l8RRvkyjcuZFo /E3ozwapMxdQ+Ya7L4n2bv0dhn/y3VdiXIM4JFi4lKecTaq8fuMuNVPG6rQWQ8NSSH0+/zjw0r2 4l7rVdMyKTkJMoDvetQS0oUKNfHjWiq43e8jM8fm6Lhtl5cfOu5jgF3zkK+b5UmtVLgSuXRahl0 kbCQz6KXV4dhye0QtRucxflBmALYeC3C9Y1WvCI0Z3/k1I/vjMGU6scvxJLaVLko1ODrHXzW7HW hn5JieWW X-Authority-Analysis: v=2.4 cv=EJkG00ZC c=1 sm=1 tr=0 ts=68be8767 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=yJojWOMRYYMA:10 a=IpJZQVW2AAAA:8 a=gAnH3GRIAAAA:8 a=EjsUJ71QB-Y5E-vLWTcA:9 a=IawgGOuG5U0WyFbmm1f5:22 X-Proofpoint-ORIG-GUID: tv7kte5n4s0wlQYMnutpOhrh4Cy2QSEy X-Proofpoint-GUID: tv7kte5n4s0wlQYMnutpOhrh4Cy2QSEy X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-08_02,2025-09-04_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 impostorscore=0 malwarescore=0 clxscore=1015 bulkscore=0 phishscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509080035 Content-Type: text/plain; charset="utf-8" Add support for IIO_ALTCURRENT channel type to distinguish AC current measurements from DC current measurements. This follows the same pattern as IIO_VOLTAGE and IIO_ALTVOLTAGE. Reviewed-by: David Lechner Signed-off-by: Antoniu Miclaus --- no changes in v7. drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-cor= e.c index f13c3aa470d7..8c9098668772 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -97,6 +97,7 @@ static const char * const iio_chan_type_name_spec[] =3D { [IIO_COLORTEMP] =3D "colortemp", [IIO_CHROMATICITY] =3D "chromaticity", [IIO_ATTENTION] =3D "attention", + [IIO_ALTCURRENT] =3D "altcurrent", }; =20 static const char * const iio_modifier_names[] =3D { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 3eb0821af7a4..3c3cc1497a1e 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -52,6 +52,7 @@ enum iio_chan_type { IIO_COLORTEMP, IIO_CHROMATICITY, IIO_ATTENTION, + IIO_ALTCURRENT, }; =20 enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index eab7b082f19d..d26aff649f3f 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -64,6 +64,7 @@ static const char * const iio_chan_type_name_spec[] =3D { [IIO_COLORTEMP] =3D "colortemp", [IIO_CHROMATICITY] =3D "chromaticity", [IIO_ATTENTION] =3D "attention", + [IIO_ALTCURRENT] =3D "altcurrent", }; =20 static const char * const iio_ev_type_text[] =3D { @@ -187,6 +188,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_COLORTEMP: case IIO_CHROMATICITY: case IIO_ATTENTION: + case IIO_ALTCURRENT: break; default: return false; --=20 2.43.0 From nobody Fri Oct 3 02:16:59 2025 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 990672E7BCB; Mon, 8 Sep 2025 07:36:14 +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=1757316976; cv=none; b=uUMpm3Y3FnNSot3ccEoaCLRpg1lJYR88UtCpyHjM7ESf3GPmeu/z33Hof20H+pLThDEN12amoigmUGH2+C2VDpXs4K6yC2t2O6qtQYL4d3DsjrSHRHfGKkWXqlzH8LeZg6d+UDGNfDDedTE2F/rZ2ArwGMkcQ8x/OHckz++4k8o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316976; c=relaxed/simple; bh=JZrJ85i5faqjawGQ6N84C3rWLvF1iJ6SNx9DsYfDw4U=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aAosLeKPgA+nBD5vPkRkeuNq0M4uOUVfEDZB9KLRLuA9IUzr70EQCS0MD7EC/XjgF2R2OJyrfNMk0mJFecko+lKnBL0sfJMsRUoYiI3o5wy1KK7yoNqzsK//taXq9+76K7ohevM0NUXafauzOCv7BhkueubSLsdpTTHwx1p1QCQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none 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=CPV0OTlG; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none 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="CPV0OTlG" Received: from pps.filterd (m0375855.ppops.net [127.0.0.1]) by mx0b-00128a01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 5883xACS003822; Mon, 8 Sep 2025 03:36:06 -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=+7/kG scdwGNsDembX2CrKkaVRxiDahJiGIH+Ixxor4o=; b=CPV0OTlGjRtQBFIYk6mXD yXJjHsHbs4oRU6hTR8TFehYzX2ADAYS9eZSMcfnyfzcJHVwE1gAfHuFtQcmsRrmn 9xVUWsvFEPb/Kq7Pm3aphOsW28sEq2UkRpuSS/xPaOomxGnwpUoSbjXrSEHOI7YP kYGifOf/7KczXTGu4A+VNeu5AEG3uUR1SDbiB1VZwkkD46hOGTt+CZzaS5lvakRA eBK9puytv9huYwk9DoKUD2+yF4ZLN6d9e9G1R10iZgKxWcs/2qI9wS1e/zSKzgzz 9FXBlFdFImHNHoBlcNHurXzdoKc6sjwXmS2trW3afNsCVq5m0ASjCxrhNzdCNbvk g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 491qqfguff-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 Sep 2025 03:36:06 -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 5887a5fp036430 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 8 Sep 2025 03:36:05 -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.10; Mon, 8 Sep 2025 03:36:05 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB4.ad.analog.com (10.64.17.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 8 Sep 2025 03:36:05 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 8 Sep 2025 03:36:05 -0400 Received: from Ubuntu.ad.analog.com ([10.132.255.227]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 5887ZpEe004718; Mon, 8 Sep 2025 03:35:59 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v7 2/6] iio: add power and energy measurement modifiers Date: Mon, 8 Sep 2025 07:35:22 +0000 Message-ID: <20250908073531.3639-3-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908073531.3639-1-antoniu.miclaus@analog.com> References: <20250908073531.3639-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-Spam-Details-Enc: AW1haW4tMjUwOTA4MDAzNSBTYWx0ZWRfX8A9yOVfQ/NSc CQI+TjWsqAJD2CrlesV7ksKrXQJ9SC+f532T4iR7k3wVb2YTJvkMOEvPAisHpzaUvhhPCmSfI3Z 9/fdiDMlUf1EB4qILexkJB7nFlFWOAqk/QKb0EaytTLjpvs52AnMTvnid/ZV6nML+/6iun/wOul a9AuP6rlEjJlgfww6kOGKM9TBnNhcUq8EaO7tMmTDa9MjPoG73K3gvuGXdIj1UONleMNPmkj3cs INN1bB3uUo0dBTMMVl47a3QCAO3Ult83JBwGFna8odRNocqZ2hsaz1qDnOzKd86cE+E5cqFEGt3 re0wlJ/a2HD3+w9yzvPBgNi6daXd0OdcUDJ0dkiBHxhUCgGO1v8gu1xKsDs2jXeP3EiYmH2oGl9 cgAHPxkG X-Authority-Analysis: v=2.4 cv=EJkG00ZC c=1 sm=1 tr=0 ts=68be8766 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=yJojWOMRYYMA:10 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=4CwWzBU9b3dOdXpWUEUA:9 X-Proofpoint-ORIG-GUID: LCyPoWgBDwUebgsurMCD3h4laXhlbEo_ X-Proofpoint-GUID: LCyPoWgBDwUebgsurMCD3h4laXhlbEo_ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-08_02,2025-09-04_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 impostorscore=0 malwarescore=0 clxscore=1015 bulkscore=0 phishscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509080035 Content-Type: text/plain; charset="utf-8" Add new IIO modifiers to support power and energy measurement devices: Power modifiers: - IIO_MOD_ACTIVE: Real power consumed by the load - IIO_MOD_REACTIVE: Power that oscillates between source and load - IIO_MOD_APPARENT: Magnitude of complex power Signal quality modifiers: - IIO_MOD_RMS: Root Mean Square value Additionally adds: - IIO_CHAN_INFO_POWERFACTOR: Power factor channel info type for representing the ratio of active power to apparent power These modifiers enable proper representation of power measurement devices like energy meters and power analyzers. Signed-off-by: Antoniu Miclaus --- changes in v7: - add modifier names to tools/iio/iio_event_monitor.c Documentation/ABI/testing/sysfs-bus-iio | 29 +++++++++++++++++++++++++ drivers/iio/industrialio-core.c | 5 +++++ include/linux/iio/types.h | 1 + include/uapi/linux/iio/types.h | 4 ++++ tools/iio/iio_event_monitor.c | 8 +++++++ 5 files changed, 47 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/te= sting/sysfs-bus-iio index 2fb2cea4b192..78da68826307 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -167,7 +167,18 @@ Description: is required is a consistent labeling. Units after application of scale and offset are millivolts. =20 +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_rms_raw +KernelVersion: 6.18 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled) Root Mean Square (RMS) voltage measurement from + channel Y. Units after application of scale and offset are + millivolts. + What: /sys/bus/iio/devices/iio:deviceX/in_powerY_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_active_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_reactive_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_apparent_raw KernelVersion: 4.5 Contact: linux-iio@vger.kernel.org Description: @@ -176,6 +187,13 @@ Description: unique to allow association with event codes. Units after application of scale and offset are milliwatts. =20 +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_powerfactor +KernelVersion: 6.18 +Contact: linux-iio@vger.kernel.org +Description: + Power factor measurement from channel Y. Power factor is the + ratio of active power to apparent power. The value is unitless. + What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw KernelVersion: 3.2 Contact: linux-iio@vger.kernel.org @@ -1569,6 +1587,9 @@ Description: =20 What: /sys/.../iio:deviceX/in_energy_input What: /sys/.../iio:deviceX/in_energy_raw +What: /sys/.../iio:deviceX/in_energyY_active_raw +What: /sys/.../iio:deviceX/in_energyY_reactive_raw +What: /sys/.../iio:deviceX/in_energyY_apparent_raw KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: @@ -1707,6 +1728,14 @@ Description: component of the signal while the 'q' channel contains the quadrature component. =20 +What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_rms_raw +KernelVersion: 6.18 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled no bias removal etc.) Root Mean Square (RMS) current + measurement from channel Y. Units after application of scale and + offset are milliamps. + What: /sys/.../iio:deviceX/in_energy_en What: /sys/.../iio:deviceX/in_distance_en What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-cor= e.c index 8c9098668772..9e372ed38552 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -153,6 +153,10 @@ static const char * const iio_modifier_names[] =3D { [IIO_MOD_PITCH] =3D "pitch", [IIO_MOD_YAW] =3D "yaw", [IIO_MOD_ROLL] =3D "roll", + [IIO_MOD_RMS] =3D "rms", + [IIO_MOD_ACTIVE] =3D "active", + [IIO_MOD_REACTIVE] =3D "reactive", + [IIO_MOD_APPARENT] =3D "apparent", }; =20 /* relies on pairs of these shared then separate */ @@ -190,6 +194,7 @@ static const char * const iio_chan_info_postfix[] =3D { [IIO_CHAN_INFO_ZEROPOINT] =3D "zeropoint", [IIO_CHAN_INFO_TROUGH] =3D "trough_raw", [IIO_CHAN_INFO_CONVDELAY] =3D "convdelay", + [IIO_CHAN_INFO_POWERFACTOR] =3D "powerfactor", }; /** * iio_device_id() - query the unique ID for the device diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index ad2761efcc83..34eebad12d2c 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -70,6 +70,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_ZEROPOINT, IIO_CHAN_INFO_TROUGH, IIO_CHAN_INFO_CONVDELAY, + IIO_CHAN_INFO_POWERFACTOR, }; =20 #endif /* _IIO_TYPES_H_ */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 3c3cc1497a1e..6d269b844271 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -109,6 +109,10 @@ enum iio_modifier { IIO_MOD_ROLL, IIO_MOD_LIGHT_UVA, IIO_MOD_LIGHT_UVB, + IIO_MOD_RMS, + IIO_MOD_ACTIVE, + IIO_MOD_REACTIVE, + IIO_MOD_APPARENT, }; =20 enum iio_event_type { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index d26aff649f3f..03ca33869ce8 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -141,6 +141,10 @@ static const char * const iio_modifier_names[] =3D { [IIO_MOD_PITCH] =3D "pitch", [IIO_MOD_YAW] =3D "yaw", [IIO_MOD_ROLL] =3D "roll", + [IIO_MOD_RMS] =3D "rms", + [IIO_MOD_ACTIVE] =3D "active", + [IIO_MOD_REACTIVE] =3D "reactive", + [IIO_MOD_APPARENT] =3D "apparent", }; =20 static bool event_is_known(struct iio_event_data *event) @@ -240,6 +244,10 @@ static bool event_is_known(struct iio_event_data *even= t) case IIO_MOD_PM4: case IIO_MOD_PM10: case IIO_MOD_O2: + case IIO_MOD_RMS: + case IIO_MOD_ACTIVE: + case IIO_MOD_REACTIVE: + case IIO_MOD_APPARENT: break; default: return false; --=20 2.43.0 From nobody Fri Oct 3 02:16:59 2025 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 A87052E2EFC; Mon, 8 Sep 2025 07:36:19 +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=1757316982; cv=none; b=LBRn1RPzRuT3Ng3FtGdOal4HDgeNHT3Ee++zAH66O3tb1qmiJLCyGlGRjedwo9M0PetBMzcQ5TMfKoeJeMInD5d9jBv8dXCSE2aC6UQptOy/aU4yVkZAf2VpXqF8Bl4Ojtitqde/ArvMzRngbfAknye+kfcAr+xiVvO6zpzeml0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316982; c=relaxed/simple; bh=Jn6V+AEwc7CC0ffKiXzHfAqsC9IkRTzIzspx+OcmKq0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=emJs0M/13VyT4iXmjUrKAhwfX4gQQArBa4zy6TqG13KhGPIspHgwdXPEu+UPTnxz/eevStTKrhrn9rchHXfnzpnOf9ZW7Ouqd5b98iqIMY6j7nyMXyPdnireqcSyjBENo2AcvbIqmn9fQ5JSgkdSnILHOYXLufANtucGRueAjhc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none 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=d+b/de7v; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none 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="d+b/de7v" Received: from pps.filterd (m0375855.ppops.net [127.0.0.1]) by mx0b-00128a01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 588403RB005861; Mon, 8 Sep 2025 03:36:11 -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=nBmSj YinlLxzNCEpFHvdrYz5n9tRwrfunXazhluhcis=; b=d+b/de7vlkpFVNqROKIwy PqKHnPkBQ/0pYiKCghzgD4foXKX6gYPWA0ziib1Xth5p89ushokeYjUyHCAYDqKn HwEu9QJOSS/nNjpkuqcgylbMaLBjwWkbLjvnaku1m54FUxH3fh5D8ZLooxOmH4D1 uoFUVThKwuZDgkGMArDYABU89gANO0PNDL7tZKKVGGMud5F5DsckrsVQzWfmC+dl F8+z3TJsD6M8yZIpHWz6gV6JjDxMe1w4y8/ClBZ/DUbF64x/WGVA4qSXqd/9KdRZ htrTlkorswYupjobO9QrlIHC4LpiqTw8bCQQOXsDWJOc0adl3yCpCgK+MCu3MyV2 Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 491qqfgufu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 Sep 2025 03:36:10 -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 5887a9HH036463 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 8 Sep 2025 03:36:09 -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.10; Mon, 8 Sep 2025 03:36:09 -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.10 via Frontend Transport; Mon, 8 Sep 2025 03:36:09 -0400 Received: from Ubuntu.ad.analog.com ([10.132.255.227]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 5887ZpEf004718; Mon, 8 Sep 2025 03:36:01 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v7 3/6] dt-bindings: iio: adc: add ade9000 Date: Mon, 8 Sep 2025 07:35:23 +0000 Message-ID: <20250908073531.3639-4-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908073531.3639-1-antoniu.miclaus@analog.com> References: <20250908073531.3639-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA4MDAzNSBTYWx0ZWRfX3WRkkJqiEKga qvbjou9iDBexdX86D8bTYsHxMxp0KuD1oVmh8ZXAzCy/YvBeuEbOuGaTZJxG9Jq7H+K3Ksq8pBq XXfWoNaTyVIMuiLdQNpP/H+/OU5EwOZXE49JK78DI9/18ubKtMjadKd0Py9ISwnkhzQMxHMs9Pk Z9whyqRVqRgm7WGJn+dvpuaTbuYS21VmQraN46WKMSKDt3hVDiW7qkvjGYj+OQhR7ciuRYnIgtA a0RQB5PpLk9k04XkyRyhammqPhOugmOocG/fWO3Z2oM+7UvFdryAcd/6gM2LaRnuxsDPGy7fivA TUI4/QTNnQzUY7mrPujW81SerokPhoC4sZmbPfUbELjxUP/DG3MtzG1Gl7aKEq7PhYN0wKWhHDq +/qgVeK2 X-Authority-Analysis: v=2.4 cv=EJkG00ZC c=1 sm=1 tr=0 ts=68be876a cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=gEfo2CItAAAA:8 a=gAnH3GRIAAAA:8 a=_AvCwROysrFvSXfO5EcA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-ORIG-GUID: 5zFUPtNN0nj0dREVhNU9bZiq--7MoQZa X-Proofpoint-GUID: 5zFUPtNN0nj0dREVhNU9bZiq--7MoQZa X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-08_02,2025-09-04_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 impostorscore=0 malwarescore=0 clxscore=1015 bulkscore=0 phishscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509080035 Add devicetree bindings support for ade9000. Signed-off-by: Antoniu Miclaus Reviewed-by: Conor Dooley --- changes in v7: - remove clock-names property and example usage .../bindings/iio/adc/adi,ade9000.yaml | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ade9000.y= aml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml b/D= ocumentation/devicetree/bindings/iio/adc/adi,ade9000.yaml new file mode 100644 index 000000000000..bd429552d568 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2025 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ade9000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADE9000 High Performance, Polyphase Energy Metering + +maintainers: + - Antoniu Miclaus + +description: | + The ADE9000 is a highly accurate, fully integrated, multiphase energy an= d power + quality monitoring device. Superior analog performance and a digital sig= nal + processing (DSP) core enable accurate energy monitoring over a wide dyna= mic + range. An integrated high end reference ensures low drift over temperatu= re + with a combined drift of less than =C2=B125 ppm/=C2=B0C maximum for the = entire channel + including a programmable gain amplifier (PGA) and an analog-to-digital + converter (ADC). + + https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9= 000.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ade9000 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 20000000 + + interrupts: + maxItems: 3 + + interrupt-names: + items: + enum: [irq0, irq1, dready] + minItems: 1 + maxItems: 3 + + reset-gpios: + description: + Must be the device tree identifier of the RESET pin. As the line is + active low, it should be marked GPIO_ACTIVE_LOW. + maxItems: 1 + + vdd-supply: true + + vref-supply: true + + clocks: + description: External clock source when not using crystal + maxItems: 1 + + + "#clock-cells": + description: + ADE9000 can provide clock output via CLKOUT pin with external buffer. + const: 0 + +required: + - compatible + - reg + - vdd-supply + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + adc@0 { + compatible =3D "adi,ade9000"; + reg =3D <0>; + spi-max-frequency =3D <7000000>; + + #clock-cells =3D <0>; + reset-gpios =3D <&gpio 4 GPIO_ACTIVE_LOW>; + interrupts =3D <2 IRQ_TYPE_EDGE_FALLING>, <3 IRQ_TYPE_EDGE_FALLI= NG>, <4 IRQ_TYPE_EDGE_FALLING>; + interrupt-names =3D "irq0", "irq1", "dready"; + interrupt-parent =3D <&gpio>; + clocks =3D <&ext_clock_24576khz>; + vdd-supply =3D <&vdd_reg>; + }; + }; --=20 2.43.0 From nobody Fri Oct 3 02:16:59 2025 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 25EC12E7BD9; Mon, 8 Sep 2025 07:36:14 +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=1757316978; cv=none; b=gsHDX+cyfwEa+k29VqVmjqu/LRP8DB6O2jAWCCRuOnf2NoF/tYGpi6lFj3xBtIYIWBqX+48/AgktFpXxvwi98oiRDFjQFMu7O0WvCFX6GMBSeKh0XlJ4yjg+HMrf+4gtpLREMoxophOZN7qYMMeDFdwm4lopGNPLnGPc5/fPQlM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316978; c=relaxed/simple; bh=O6tOMIA3mqDPyy/9CH4Y7AfcTwBmu/nPF+JLBvhCwKM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=h5xblKYsdFpPv7OC4RvKym3pcIPsrq7Hs8hu4/tPPp8DKcywej/SuWk7AZEI/XxbexZNj4RAX/TW/pprHVokbVqkJhxmVW+o8mZcAiWNuCnZYw+8F1F+joUTSDt+e14OLs4H7KdK38Vngn23j35O4h6hMvSTYxjCWtLqUEvIgUk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none 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=eBI6deOH; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none 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="eBI6deOH" Received: from pps.filterd (m0167089.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 5886d42Z030973; Mon, 8 Sep 2025 03:36:10 -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=mnJoV XF6hvUO0xEOIyWUJMEuQQNXsJ5P6D9OjyhSKPQ=; b=eBI6deOHwPdJL9kLu3nCL 9bnatk3cT3lt/MGFBwQECd3DAeBTanM72ndDY5425Ff4nOmGwkBOe1SjpRTmJSXg /FSGy3peEtqJqj0d52u3oxDbZu5HvbtXvwj/IxohN/IyqQDQi9AwCTDDsCkOGZoZ CF+6gMCe4xDlO94JDWyKtgHideexcb1QUlbR7pGw1P1fNsxOtSDwABmYL+BF3tMR tuTSiewqSKflfY96pW4XgYOcyjHpvf1ZhdM25xzdqWgz3qhvveFl+KXxMfR2DAIh oIA8yvIdHeXmB5pxBXljMsqUbrKlpvLt5+xTi16easigOMyqNi8eZj41pjljdeta g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 491h0na9hr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 Sep 2025 03:36:10 -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 5887a8Yc036457 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 8 Sep 2025 03:36:08 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 8 Sep 2025 03:36:08 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 8 Sep 2025 03:36:08 -0400 Received: from Ubuntu.ad.analog.com ([10.132.255.227]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 5887ZpEg004718; Mon, 8 Sep 2025 03:36:02 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v7 4/6] iio: adc: add ade9000 support Date: Mon, 8 Sep 2025 07:35:24 +0000 Message-ID: <20250908073531.3639-5-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908073531.3639-1-antoniu.miclaus@analog.com> References: <20250908073531.3639-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Authority-Analysis: v=2.4 cv=H4rbw/Yi c=1 sm=1 tr=0 ts=68be876a cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=gAnH3GRIAAAA:8 a=SiOIK2hf8VEjoXFiRjMA:9 a=tMvf3xh9P1GmwA9M:21 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA3MDIxMiBTYWx0ZWRfX9vvg26OV3OYC 0nYYg+sAu2PTe1vLuH+CmnW5tfSiLGu1E7vfRAHWohbimpqK5V0shbDsveHxsvd+iZZ3beZnvzH xTU5dk4bhkyE2og2Nt6azFiy+pxx1UvzMIGEN+xDYhs/WgmqKf7YPYYRIRhQ1JK29PcscEnh3O0 NJt8Q/A+cUy8vNMALjZuaGwBNYalACs2OvR5LuYcJj7idmMGppmO5rCgMvfjcS/g4CpZJcnFJWn XCW+6fImez0+1VJHg+8cwRfvEg2rd3NaZM62NtGj56VTPcWqw0EmcB2trVaOlaLLo+ZCnglQUWa 0jckAvpFBrsDXzPSJhQoic/KNuOEKy14PTPkMrRsYpJz1gFAghjiduAAnM1bKfl8BVwHonB0XuS Z/OHAjUj X-Proofpoint-GUID: 1426q12FoO6MZlqJePGdmE9xP2X_Bedi X-Proofpoint-ORIG-GUID: 1426q12FoO6MZlqJePGdmE9xP2X_Bedi X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-08_02,2025-09-04_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 bulkscore=0 impostorscore=0 spamscore=0 adultscore=0 clxscore=1015 suspectscore=0 phishscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509070212 Add driver support for the ade9000. highly accurate, fully integrated, multiphase energy and power quality monitoring device. Signed-off-by: Antoniu Miclaus --- changes in v7: - remove custom clock output implementation, use standard divider clock - remove system frequency and PGA gain configuration channel - remove support for frequency and shared scale info masks - add max_register to regmap configuration - improve interrupt handling for optional interrupts - add comprehensive error logging for invalid event configurations - simplify event handling code paths and remove unreachable code - move vref regulator handling later in probe sequence - remove unused include files (iio/sysfs.h, duplicate interrupt.h) - add CONFIG_COMMON_CLK guard for clock functionality - consolidate error handling patterns throughout driver drivers/iio/adc/Kconfig | 19 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ade9000.c | 1793 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1813 insertions(+) create mode 100644 drivers/iio/adc/ade9000.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6de2abad0197..53bdd34a5899 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -507,6 +507,25 @@ config AD9467 To compile this driver as a module, choose M here: the module will be called ad9467. =20 +config ADE9000 + tristate "Analog Devices ADE9000 Multiphase Energy, and Power Quality Mon= itoring IC Driver" + depends on SPI + select REGMAP_SPI + select IIO_BUFFER + select IIO_KFIFO_BUF + help + Say yes here to build support for the Analog Devices ADE9000, + a highly accurate, multiphase energy and power quality monitoring + integrated circuit. + + The device features high-precision analog-to-digital converters + and digital signal processing to compute RMS values, power factor, + frequency, and harmonic analysis. It supports SPI communication + and provides buffered data output through the IIO framework. + + To compile this driver as a module, choose M here: the module will + be called ade9000. + config ADI_AXI_ADC tristate "Analog Devices Generic AXI ADC IP core driver" depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_= SOCFPGA || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 1c6ca5fd4b6d..e3ef416a3b5b 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_AD7944) +=3D ad7944.o obj-$(CONFIG_AD7949) +=3D ad7949.o obj-$(CONFIG_AD799X) +=3D ad799x.o obj-$(CONFIG_AD9467) +=3D ad9467.o +obj-$(CONFIG_ADE9000) +=3D ade9000.o obj-$(CONFIG_ADI_AXI_ADC) +=3D adi-axi-adc.o obj-$(CONFIG_ASPEED_ADC) +=3D aspeed_adc.o obj-$(CONFIG_AT91_ADC) +=3D at91_adc.o diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c new file mode 100644 index 000000000000..a3be4bd24686 --- /dev/null +++ b/drivers/iio/adc/ade9000.c @@ -0,0 +1,1793 @@ +// SPDX-License-Identifier: GPL-2.0-only +/** + * ADE9000 driver + * + * Copyright 2025 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Address of ADE9000 registers */ +#define ADE9000_REG_AIGAIN 0x000 +#define ADE9000_REG_AVGAIN 0x00B +#define ADE9000_REG_AIRMSOS 0x00C +#define ADE9000_REG_AVRMSOS 0x00D +#define ADE9000_REG_APGAIN 0x00E +#define ADE9000_REG_AWATTOS 0x00F +#define ADE9000_REG_AVAROS 0x010 +#define ADE9000_REG_AFVAROS 0x012 +#define ADE9000_REG_CONFIG0 0x060 +#define ADE9000_REG_DICOEFF 0x072 +#define ADE9000_REG_AI_PCF 0x20A +#define ADE9000_REG_AV_PCF 0x20B +#define ADE9000_REG_AIRMS 0x20C +#define ADE9000_REG_AVRMS 0x20D +#define ADE9000_REG_AWATT 0x210 +#define ADE9000_REG_AVAR 0x211 +#define ADE9000_REG_AVA 0x212 +#define ADE9000_REG_AFVAR 0x214 +#define ADE9000_REG_APF 0x216 +#define ADE9000_REG_BI_PCF 0x22A +#define ADE9000_REG_BV_PCF 0x22B +#define ADE9000_REG_BIRMS 0x22C +#define ADE9000_REG_BVRMS 0x22D +#define ADE9000_REG_CI_PCF 0x24A +#define ADE9000_REG_CV_PCF 0x24B +#define ADE9000_REG_CIRMS 0x24C +#define ADE9000_REG_CVRMS 0x24D +#define ADE9000_REG_AWATT_ACC 0x2E5 +#define ADE9000_REG_AWATTHR_LO 0x2E6 +#define ADE9000_REG_AVAHR_LO 0x2FA +#define ADE9000_REG_AFVARHR_LO 0x30E +#define ADE9000_REG_BWATTHR_LO 0x322 +#define ADE9000_REG_BVAHR_LO 0x336 +#define ADE9000_REG_BFVARHR_LO 0x34A +#define ADE9000_REG_CWATTHR_LO 0x35E +#define ADE9000_REG_CVAHR_LO 0x372 +#define ADE9000_REG_CFVARHR_LO 0x386 +#define ADE9000_REG_STATUS0 0x402 +#define ADE9000_REG_STATUS1 0x403 +#define ADE9000_REG_MASK0 0x405 +#define ADE9000_REG_MASK1 0x406 +#define ADE9000_REG_EVENT_MASK 0x407 +#define ADE9000_REG_VLEVEL 0x40F +#define ADE9000_REG_DIP_LVL 0x410 +#define ADE9000_REG_DIPA 0x411 +#define ADE9000_REG_DIPB 0x412 +#define ADE9000_REG_DIPC 0x413 +#define ADE9000_REG_SWELL_LVL 0x414 +#define ADE9000_REG_SWELLA 0x415 +#define ADE9000_REG_SWELLB 0x416 +#define ADE9000_REG_SWELLC 0x417 +#define ADE9000_REG_APERIOD 0x418 +#define ADE9000_REG_BPERIOD 0x419 +#define ADE9000_REG_CPERIOD 0x41A +#define ADE9000_REG_RUN 0x480 +#define ADE9000_REG_CONFIG1 0x481 +#define ADE9000_REG_ACCMODE 0x492 +#define ADE9000_REG_CONFIG3 0x493 +#define ADE9000_REG_ZXTOUT 0x498 +#define ADE9000_REG_ZX_LP_SEL 0x49A +#define ADE9000_REG_WFB_CFG 0x4A0 +#define ADE9000_REG_WFB_PG_IRQEN 0x4A1 +#define ADE9000_REG_WFB_TRG_CFG 0x4A2 +#define ADE9000_REG_WFB_TRG_STAT 0x4A3 +#define ADE9000_REG_CONFIG2 0x4AF +#define ADE9000_REG_EP_CFG 0x4B0 +#define ADE9000_REG_EGY_TIME 0x4B2 +#define ADE9000_REG_PGA_GAIN 0x4B9 +#define ADE9000_REG_VERSION 0x4FE +#define ADE9000_REG_WF_BUFF 0x800 +#define ADE9000_REG_WF_HALF_BUFF 0xC00 + +#define ADE9000_REG_ADDR_MASK GENMASK(15, 4) +#define ADE9000_REG_READ_BIT_MASK BIT(3) + +#define ADE9000_WF_CAP_EN_MASK BIT(4) +#define ADE9000_WF_CAP_SEL_MASK BIT(5) +#define ADE9000_WF_MODE_MASK GENMASK(7, 6) +#define ADE9000_WF_SRC_MASK GENMASK(9, 8) +#define ADE9000_WF_IN_EN_MASK BIT(12) + +/* External reference selection bit in CONFIG1 */ +#define ADE9000_EXT_REF_MASK BIT(15) + +/* + * Configuration registers + */ +#define ADE9000_PGA_GAIN 0x0000 + +/* Default configuration */ + +#define ADE9000_CONFIG0 0x00000000 + +/* CF3/ZX pin outputs Zero crossing, CF4 =3D DREADY */ +#define ADE9000_CONFIG1 0x000E + +/* Default High pass corner frequency of 1.25Hz */ +#define ADE9000_CONFIG2 0x0A00 + +/* Peak and overcurrent detection disabled */ +#define ADE9000_CONFIG3 0x0000 + +/* + * 50Hz operation, 3P4W Wye configuration, signed accumulation + * 3P4W Wye =3D 3-Phase 4-Wire star configuration (3 phases + neutral wire) + * Clear bit 8 i.e. ACCMODE=3D0x00xx for 50Hz operation + * ACCMODE=3D0x0x9x for 3Wire delta when phase B is used as reference + * 3Wire delta =3D 3-Phase 3-Wire triangle configuration (3 phases, no neu= tral) + */ +#define ADE9000_ACCMODE 0x0000 +#define ADE9000_ACCMODE_60HZ 0x0100 + +/*Line period and zero crossing obtained from VA */ +#define ADE9000_ZX_LP_SEL 0x0000 + +/* Interrupt mask values for initialization */ +#define ADE9000_MASK0_ALL_INT_DIS 0 +#define ADE9000_MASK1_ALL_INT_DIS 0x00000000 + +/* Events disabled */ +#define ADE9000_EVENT_DISABLE 0x00000000 + +/* + * Assuming Vnom=3D1/2 of full scale. + * Refer to Technical reference manual for detailed calculations. + */ +#define ADE9000_VLEVEL 0x0022EA28 + +/* Set DICOEFF=3D 0xFFFFE000 when integrator is enabled */ +#define ADE9000_DICOEFF 0x00000000 + +/* DSP ON */ +#define ADE9000_RUN_ON 0xFFFFFFFF + +/* + * Energy Accumulation Settings + * Enable energy accumulation, accumulate samples at 8ksps + * latch energy accumulation after EGYRDY + * If accumulation is changed to half line cycle mode, change EGY_TIME + */ +#define ADE9000_EP_CFG 0x0011 + +/* Accumulate 4000 samples */ +#define ADE9000_EGY_TIME 7999 + +/* + * Constant Definitions + * ADE9000 FDSP: 8000sps, ADE9000 FDSP: 4000sps + */ +#define ADE9000_FDSP 4000 +#define ADE9000_DEFAULT_CLK_FREQ_HZ 24576000 +#define ADE9000_WFB_CFG 0x03E9 +#define ADE9000_WFB_PAGE_SIZE 128 +#define ADE9000_WFB_NR_OF_PAGES 16 +#define ADE9000_WFB_MAX_CHANNELS 8 +#define ADE9000_WFB_BYTES_IN_SAMPLE 4 +#define ADE9000_WFB_SAMPLES_IN_PAGE \ + (ADE9000_WFB_PAGE_SIZE / ADE9000_WFB_MAX_CHANNELS) +#define ADE9000_WFB_MAX_SAMPLES_CHAN \ + (ADE9000_WFB_SAMPLES_IN_PAGE * ADE9000_WFB_NR_OF_PAGES) +#define ADE9000_WFB_FULL_BUFF_NR_SAMPLES \ + (ADE9000_WFB_PAGE_SIZE * ADE9000_WFB_NR_OF_PAGES) +#define ADE9000_WFB_FULL_BUFF_SIZE \ + (ADE9000_WFB_FULL_BUFF_NR_SAMPLES * ADE9000_WFB_BYTES_IN_SAMPLE) + +#define ADE9000_SWRST_BIT BIT(0) + +/* Status and Mask register bits*/ +#define ADE9000_ST0_WFB_TRIG_BIT BIT(16) +#define ADE9000_ST0_PAGE_FULL_BIT BIT(17) +#define ADE9000_ST0_EGYRDY BIT(0) + +#define ADE9000_ST1_ZXTOVA_BIT BIT(6) +#define ADE9000_ST1_ZXTOVB_BIT BIT(7) +#define ADE9000_ST1_ZXTOVC_BIT BIT(8) +#define ADE9000_ST1_ZXVA_BIT BIT(9) +#define ADE9000_ST1_ZXVB_BIT BIT(10) +#define ADE9000_ST1_ZXVC_BIT BIT(11) +#define ADE9000_ST1_ZXIA_BIT BIT(13) +#define ADE9000_ST1_ZXIB_BIT BIT(14) +#define ADE9000_ST1_ZXIC_BIT BIT(15) +#define ADE9000_ST1_RSTDONE_BIT BIT(16) +#define ADE9000_ST1_SEQERR_BIT BIT(18) +#define ADE9000_ST1_SWELLA_BIT BIT(20) +#define ADE9000_ST1_SWELLB_BIT BIT(21) +#define ADE9000_ST1_SWELLC_BIT BIT(22) +#define ADE9000_ST1_DIPA_BIT BIT(23) +#define ADE9000_ST1_DIPB_BIT BIT(24) +#define ADE9000_ST1_DIPC_BIT BIT(25) +#define ADE9000_ST1_ERROR0_BIT BIT(28) +#define ADE9000_ST1_ERROR1_BIT BIT(29) +#define ADE9000_ST1_ERROR2_BIT BIT(30) +#define ADE9000_ST1_ERROR3_BIT BIT(31) +#define ADE9000_ST_ERROR \ + (ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \ + ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3) +#define ADE9000_ST1_CROSSING_FIRST 6 +#define ADE9000_ST1_CROSSING_DEPTH 25 + +#define ADE9000_WFB_TRG_DIP_BIT BIT(0) +#define ADE9000_WFB_TRG_SWELL_BIT BIT(1) +#define ADE9000_WFB_TRG_ZXIA_BIT BIT(3) +#define ADE9000_WFB_TRG_ZXIB_BIT BIT(4) +#define ADE9000_WFB_TRG_ZXIC_BIT BIT(5) +#define ADE9000_WFB_TRG_ZXVA_BIT BIT(6) +#define ADE9000_WFB_TRG_ZXVB_BIT BIT(7) +#define ADE9000_WFB_TRG_ZXVC_BIT BIT(8) + +/* Stop when waveform buffer is full */ +#define ADE9000_WFB_FULL_MODE 0x0 +/* Continuous fill=E2=80=94stop only on enabled trigger events */ +#define ADE9000_WFB_EN_TRIG_MODE 0x1 +/* Continuous filling=E2=80=94center capture around enabled trigger events= */ +#define ADE9000_WFB_C_EN_TRIG_MODE 0x2 +/* Continuous fill=E2=80=94used as streaming mode for continuous data outp= ut */ +#define ADE9000_WFB_STREAMING_MODE 0x3 + +#define ADE9000_LAST_PAGE_BIT BIT(15) +#define ADE9000_MIDDLE_PAGE_BIT BIT(7) + +/* + * Full scale Codes referred from Datasheet. Respective digital codes are + * produced when ADC inputs are at full scale. + */ +#define ADE9000_RMS_FULL_SCALE_CODES 52866837 +#define ADE9000_WATT_FULL_SCALE_CODES 20694066 +#define ADE9000_PCF_FULL_SCALE_CODES 74770000 + +/* Phase and channel definitions */ +#define ADE9000_PHASE_A_NR 0 +#define ADE9000_PHASE_B_NR 1 +#define ADE9000_PHASE_C_NR 2 + +#define ADE9000_SCAN_POS_IA BIT(0) +#define ADE9000_SCAN_POS_VA BIT(1) +#define ADE9000_SCAN_POS_IB BIT(2) +#define ADE9000_SCAN_POS_VB BIT(3) +#define ADE9000_SCAN_POS_IC BIT(4) +#define ADE9000_SCAN_POS_VC BIT(5) + +/* Waveform buffer configuration values */ +enum ade9000_wfb_cfg { + ADE9000_WFB_CFG_ALL_CHAN =3D 0x0, + ADE9000_WFB_CFG_IA_VA =3D 0x1, + ADE9000_WFB_CFG_IB_VB =3D 0x2, + ADE9000_WFB_CFG_IC_VC =3D 0x3, + ADE9000_WFB_CFG_IA =3D 0x8, + ADE9000_WFB_CFG_VA =3D 0x9, + ADE9000_WFB_CFG_IB =3D 0xA, + ADE9000_WFB_CFG_VB =3D 0xB, + ADE9000_WFB_CFG_IC =3D 0xC, + ADE9000_WFB_CFG_VC =3D 0xD, +}; + +#define ADE9000_PHASE_B_POS_BIT BIT(5) +#define ADE9000_PHASE_C_POS_BIT BIT(6) + +#define ADE9000_MAX_PHASE_NR 3 +#define AD9000_CHANNELS_PER_PHASE 10 + +/* + * Calculate register address for multi-phase device. + * Phase A (chan 0): base address + 0x00 + * Phase B (chan 1): base address + 0x20 + * Phase C (chan 2): base address + 0x40 + */ +#define ADE9000_ADDR_ADJUST(addr, chan) \ + (((chan) =3D=3D 0 ? 0 : (chan) =3D=3D 1 ? 2 : 4) << 4 | (addr)) + +struct ade9000_state { + struct completion reset_completion; + struct mutex lock; /* Protects SPI transactions */ + u8 wf_src; + u32 wfb_trg; + u8 wfb_nr_activ_chan; + u32 wfb_nr_samples; + struct spi_device *spi; + struct clk *clkin; + struct spi_transfer xfer[2]; + struct spi_message spi_msg; + struct regmap *regmap; + union{ + u8 byte[ADE9000_WFB_FULL_BUFF_SIZE]; + __be32 word[ADE9000_WFB_FULL_BUFF_NR_SAMPLES]; + } rx_buff __aligned(IIO_DMA_MINALIGN); + u8 tx_buff[2] __aligned(IIO_DMA_MINALIGN); + unsigned int bulk_read_buf[2]; +}; + +struct ade9000_irq1_event { + u32 bit_mask; + enum iio_chan_type chan_type; + u32 channel; + enum iio_event_type event_type; + enum iio_event_direction event_dir; +}; + +static const struct ade9000_irq1_event ade9000_irq1_events[] =3D { + { ADE9000_ST1_ZXVA_BIT, IIO_VOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRE= SH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXIA_BIT, IIO_CURRENT, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRE= SH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXVB_BIT, IIO_VOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRE= SH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXIB_BIT, IIO_CURRENT, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRE= SH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXVC_BIT, IIO_VOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRE= SH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXIC_BIT, IIO_CURRENT, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRE= SH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_SWELLA_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE= _THRESH, IIO_EV_DIR_RISING }, + { ADE9000_ST1_SWELLB_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE= _THRESH, IIO_EV_DIR_RISING }, + { ADE9000_ST1_SWELLC_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE= _THRESH, IIO_EV_DIR_RISING }, + { ADE9000_ST1_DIPA_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_T= HRESH, IIO_EV_DIR_FALLING }, + { ADE9000_ST1_DIPB_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_T= HRESH, IIO_EV_DIR_FALLING }, + { ADE9000_ST1_DIPC_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_T= HRESH, IIO_EV_DIR_FALLING }, +}; + +/* Voltage events (zero crossing on instantaneous voltage) */ +static const struct iio_event_spec ade9000_voltage_events[] =3D { + { + /* Zero crossing detection - datasheet: ZXV interrupts */ + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_EITHER, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + }, +}; + +/* Current events (zero crossing on instantaneous current) */ +static const struct iio_event_spec ade9000_current_events[] =3D { + { + /* Zero crossing detection - datasheet: ZXI interrupts */ + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_EITHER, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + }, +}; + +/* RMS voltage events (swell/sag detection on RMS values) */ +static const struct iio_event_spec ade9000_rms_voltage_events[] =3D { + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_RISING, /* RMS swell detection */ + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), + }, + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_FALLING, /* RMS sag/dip detection */ + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), + }, +}; + +static const char * const ade9000_filter_type_items[] =3D { + "sinc4", "sinc4+lp", +}; + +static const int ade9000_filter_type_values[] =3D { + 0, 2, +}; + +static int ade9000_filter_type_get(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 val; + int ret; + unsigned int i; + + ret =3D regmap_read(st->regmap, ADE9000_REG_WFB_CFG, &val); + if (ret) + return ret; + + val =3D FIELD_GET(ADE9000_WF_SRC_MASK, val); + + for (i =3D 0; i < ARRAY_SIZE(ade9000_filter_type_values); i++) { + if (ade9000_filter_type_values[i] =3D=3D val) + return i; + } + + return -EINVAL; +} + +static int ade9000_filter_type_set(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int index) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + int ret, val; + + if (index >=3D ARRAY_SIZE(ade9000_filter_type_values)) + return -EINVAL; + + val =3D ade9000_filter_type_values[index]; + + /* Update the WFB_CFG register with the new filter type */ + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_SRC_MASK, + FIELD_PREP(ADE9000_WF_SRC_MASK, val)); + if (ret) + return ret; + + /* Update cached value */ + st->wf_src =3D val; + + return 0; +} + +static const struct iio_enum ade9000_filter_type_enum =3D { + .items =3D ade9000_filter_type_items, + .num_items =3D ARRAY_SIZE(ade9000_filter_type_items), + .get =3D ade9000_filter_type_get, + .set =3D ade9000_filter_type_set, +}; + +static const struct iio_chan_spec_ext_info ade9000_ext_info[] =3D { + IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ade9000_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ade9000_filter_type= _enum), + { } +}; + +#define ADE9000_CURRENT_CHANNEL(num) { \ + .type =3D IIO_CURRENT, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AI_PCF, num), \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ + .event_spec =3D ade9000_current_events, \ + .num_event_specs =3D ARRAY_SIZE(ade9000_current_events), \ + .scan_index =3D num, \ + .indexed =3D 1, \ + .scan_type =3D { \ + .sign =3D 's', \ + .realbits =3D 32, \ + .storagebits =3D 32, \ + .endianness =3D IIO_BE, \ + }, \ +} + +#define ADE9000_VOLTAGE_CHANNEL(num) { \ + .type =3D IIO_VOLTAGE, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AV_PCF, num), \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ + .event_spec =3D ade9000_voltage_events, \ + .num_event_specs =3D ARRAY_SIZE(ade9000_voltage_events), \ + .scan_index =3D num + 1, /* interleave with current channels */ \ + .indexed =3D 1, \ + .scan_type =3D { \ + .sign =3D 's', \ + .realbits =3D 32, \ + .storagebits =3D 32, \ + .endianness =3D IIO_BE, \ + }, \ + .ext_info =3D ade9000_ext_info, \ +} + +#define ADE9000_ALTCURRENT_RMS_CHANNEL(num) { \ + .type =3D IIO_ALTCURRENT, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMS, num), \ + .channel2 =3D IIO_MOD_RMS, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) { \ + .type =3D IIO_ALTVOLTAGE, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMS, num), \ + .channel2 =3D IIO_MOD_RMS, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .event_spec =3D ade9000_rms_voltage_events, \ + .num_event_specs =3D ARRAY_SIZE(ade9000_rms_voltage_events), \ + .scan_index =3D -1 \ +} + +#define ADE9000_POWER_ACTIVE_CHANNEL(num) { \ + .type =3D IIO_POWER, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AWATT, num), \ + .channel2 =3D IIO_MOD_ACTIVE, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ + .scan_index =3D -1 \ +} + +#define ADE9000_POWER_REACTIVE_CHANNEL(num) { \ + .type =3D IIO_POWER, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AVAR, num), \ + .channel2 =3D IIO_MOD_REACTIVE, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .scan_index =3D -1 \ +} + +#define ADE9000_POWER_APPARENT_CHANNEL(num) { \ + .type =3D IIO_POWER, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AVA, num), \ + .channel2 =3D IIO_MOD_APPARENT, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index =3D -1 \ +} + + #define ADE9000_ENERGY_ACTIVE_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_ACTIVE, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ENERGY_APPARENT_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_APPARENT, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ENERGY_REACTIVE_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_REACTIVE, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_POWER_FACTOR_CHANNEL(num) { \ + .type =3D IIO_POWER, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_APF, num), \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_POWERFACTOR), \ + .scan_index =3D -1 \ +} + +static const struct iio_chan_spec ade9000_channels[] =3D { + /* Phase A channels */ + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFVARHR_L= O), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR), + /* Phase B channels */ + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFVARHR_L= O), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR), + /* Phase C channels */ + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFVARHR_L= O), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR), +}; + +static const struct reg_sequence ade9000_initialization_sequence[] =3D { + { ADE9000_REG_PGA_GAIN, ADE9000_PGA_GAIN }, + { ADE9000_REG_CONFIG0, ADE9000_CONFIG0 }, + { ADE9000_REG_CONFIG1, ADE9000_CONFIG1 }, + { ADE9000_REG_CONFIG2, ADE9000_CONFIG2 }, + { ADE9000_REG_CONFIG3, ADE9000_CONFIG3 }, + { ADE9000_REG_ACCMODE, ADE9000_ACCMODE }, + { ADE9000_REG_ZX_LP_SEL, ADE9000_ZX_LP_SEL }, + { ADE9000_REG_MASK0, ADE9000_MASK0_ALL_INT_DIS }, + { ADE9000_REG_MASK1, ADE9000_MASK1_ALL_INT_DIS }, + { ADE9000_REG_EVENT_MASK, ADE9000_EVENT_DISABLE }, + { ADE9000_REG_WFB_CFG, ADE9000_WFB_CFG }, + { ADE9000_REG_VLEVEL, ADE9000_VLEVEL }, + { ADE9000_REG_DICOEFF, ADE9000_DICOEFF }, + { ADE9000_REG_EGY_TIME, ADE9000_EGY_TIME }, + { ADE9000_REG_EP_CFG, ADE9000_EP_CFG }, + /* Clear all pending status bits by writing 1s */ + { ADE9000_REG_STATUS0, GENMASK(31, 0) }, + { ADE9000_REG_STATUS1, GENMASK(31, 0) }, + { ADE9000_REG_RUN, ADE9000_RUN_ON } +}; + +static int ade9000_spi_write_reg(void *context, unsigned int reg, + unsigned int val) +{ + struct ade9000_state *st =3D context; + u8 tx_buf[6]; + u16 addr; + int ret, len; + + guard(mutex)(&st->lock); + + addr =3D FIELD_PREP(ADE9000_REG_ADDR_MASK, reg); + put_unaligned_be16(addr, tx_buf); + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) { + put_unaligned_be16(val, &tx_buf[2]); + len =3D 4; + } else { + put_unaligned_be32(val, &tx_buf[2]); + len =3D 6; + } + + ret =3D spi_write_then_read(st->spi, tx_buf, len, NULL, 0); + if (ret) + dev_err(&st->spi->dev, "problem when writing register 0x%x\n", reg); + + return ret; +} + +static int ade9000_spi_read_reg(void *context, unsigned int reg, + unsigned int *val) +{ + struct ade9000_state *st =3D context; + u8 tx_buf[2]; + u8 rx_buf[4]; + u16 addr; + int ret, rx_len; + + guard(mutex)(&st->lock); + + addr =3D FIELD_PREP(ADE9000_REG_ADDR_MASK, reg) | + ADE9000_REG_READ_BIT_MASK; + + put_unaligned_be16(addr, tx_buf); + + /* Skip CRC bytes - only read actual data */ + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) + rx_len =3D 2; + else + rx_len =3D 4; + + ret =3D spi_write_then_read(st->spi, tx_buf, 2, rx_buf, rx_len); + if (ret) { + dev_err(&st->spi->dev, "error reading register 0x%x\n", reg); + return ret; + } + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) + *val =3D get_unaligned_be16(rx_buf); + else + *val =3D get_unaligned_be32(rx_buf); + + return 0; +} + +static bool ade9000_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + /* Interrupt/error status registers - volatile */ + case ADE9000_REG_STATUS0: + case ADE9000_REG_STATUS1: + return true; + default: + /* All other registers are non-volatile */ + return false; + } +} + +static void ade9000_configure_scan(struct iio_dev *indio_dev, u32 wfb_addr) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u16 addr; + + addr =3D FIELD_PREP(ADE9000_REG_ADDR_MASK, wfb_addr) | + ADE9000_REG_READ_BIT_MASK; + + put_unaligned_be16(addr, st->tx_buff); + + st->xfer[0].tx_buf =3D &st->tx_buff[0]; + st->xfer[0].len =3D 2; + + st->xfer[1].rx_buf =3D st->rx_buff.byte; + + /* Always use streaming mode */ + st->xfer[1].len =3D (st->wfb_nr_samples / 2) * 4; + + spi_message_init_with_transfers(&st->spi_msg, st->xfer, ARRAY_SIZE(st->xf= er)); +} + +static int ade9000_iio_push_streaming(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + struct device *dev =3D &st->spi->dev; + u32 current_page, i; + int ret; + + guard(mutex)(&st->lock); + + ret =3D spi_sync(st->spi, &st->spi_msg); + if (ret) { + dev_err_ratelimited(dev, "SPI fail in trigger handler\n"); + return ret; + } + + /* In streaming mode, only half the buffer is filled per interrupt */ + for (i =3D 0; i < st->wfb_nr_samples / 2; i +=3D st->wfb_nr_activ_chan) + iio_push_to_buffers(indio_dev, &st->rx_buff.word[i]); + + ret =3D regmap_read(st->regmap, ADE9000_REG_WFB_PG_IRQEN, ¤t_page); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB read fail\n"); + return ret; + } + + if (current_page & ADE9000_MIDDLE_PAGE_BIT) { + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_LAST_PAGE_BIT); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB write fail\n"); + return ret; + } + + ade9000_configure_scan(indio_dev, + ADE9000_REG_WF_HALF_BUFF); + } else { + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB write fail"); + return IRQ_HANDLED; + } + + ade9000_configure_scan(indio_dev, + ADE9000_REG_WF_BUFF); + } + + return 0; +} + +static int ade9000_iio_push_buffer(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + int ret; + u32 i; + + guard(mutex)(&st->lock); + + ret =3D spi_sync(st->spi, &st->spi_msg); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "SPI fail in trigger handler\n"); + return ret; + } + + for (i =3D 0; i < st->wfb_nr_samples; i +=3D st->wfb_nr_activ_chan) + iio_push_to_buffers(indio_dev, &st->rx_buff.word[i]); + + return 0; +} + +static irqreturn_t ade9000_irq0_thread(int irq, void *data) +{ + struct iio_dev *indio_dev =3D data; + struct ade9000_state *st =3D iio_priv(indio_dev); + struct device *dev =3D &st->spi->dev; + u32 handled_irq =3D 0; + u32 interrupts, status; + int ret; + + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS0, &status); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 read status fail\n"); + return IRQ_HANDLED; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK0, &interrupts); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 read mask fail\n"); + return IRQ_HANDLED; + } + + if ((status & ADE9000_ST0_PAGE_FULL_BIT) && + (interrupts & ADE9000_ST0_PAGE_FULL_BIT)) { + /* Always use streaming mode */ + ret =3D ade9000_iio_push_streaming(indio_dev); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 IIO push fail\n"); + return IRQ_HANDLED; + } + + handled_irq |=3D ADE9000_ST0_PAGE_FULL_BIT; + } + + if ((status & ADE9000_ST0_WFB_TRIG_BIT) && + (interrupts & ADE9000_ST0_WFB_TRIG_BIT)) { + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK, 0); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB fail\n"); + return IRQ_HANDLED; + } + + if (iio_buffer_enabled(indio_dev)) { + ret =3D ade9000_iio_push_buffer(indio_dev); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 IIO push fail @ WFB TRIG\n"); + return IRQ_HANDLED; + } + } + + handled_irq |=3D ADE9000_ST0_WFB_TRIG_BIT; + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS0, handled_irq); + if (ret) + dev_err_ratelimited(dev, "IRQ0 write status fail\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t ade9000_irq1_thread(int irq, void *data) +{ + struct iio_dev *indio_dev =3D data; + struct ade9000_state *st =3D iio_priv(indio_dev); + unsigned int bit =3D ADE9000_ST1_CROSSING_FIRST; + s64 timestamp =3D iio_get_time_ns(indio_dev); + u32 handled_irq =3D 0; + u32 interrupts, result, status, tmp; + DECLARE_BITMAP(interrupt_bits, ADE9000_ST1_CROSSING_DEPTH); + const struct ade9000_irq1_event *event; + int ret, i; + + if (!completion_done(&st->reset_completion)) { + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS1, &result); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "IRQ1 read status fail\n"); + return IRQ_HANDLED; + } + + if (result & ADE9000_ST1_RSTDONE_BIT) { + complete(&st->reset_completion); + /* Clear the reset done status bit */ + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS1, ADE9000_ST1_RSTDO= NE_BIT); + if (ret) + dev_err_ratelimited(&st->spi->dev, "IRQ1 clear reset status fail\n"); + } else { + dev_err_ratelimited(&st->spi->dev, "Error testing reset done\n"); + } + + return IRQ_HANDLED; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS1, &status); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "IRQ1 read status fail\n"); + return IRQ_HANDLED; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "IRQ1 read mask fail\n"); + return IRQ_HANDLED; + } + + bitmap_from_arr32(interrupt_bits, &interrupts, ADE9000_ST1_CROSSING_DEPTH= ); + for_each_set_bit_from(bit, interrupt_bits, + ADE9000_ST1_CROSSING_DEPTH) { + tmp =3D status & BIT(bit); + if (!tmp) + continue; + + event =3D NULL; + + /* Find corresponding event in lookup table */ + for (i =3D 0; i < ARRAY_SIZE(ade9000_irq1_events); i++) { + if (ade9000_irq1_events[i].bit_mask =3D=3D tmp) { + event =3D &ade9000_irq1_events[i]; + break; + } + } + + if (event) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(event->chan_type, + event->channel, + event->event_type, + event->event_dir), + timestamp); + } + handled_irq |=3D tmp; + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS1, handled_irq); + if (ret) + dev_err_ratelimited(&st->spi->dev, "IRQ1 write status fail\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t ade9000_dready_thread(int irq, void *data) +{ + struct iio_dev *indio_dev =3D data; + + /* Handle data ready interrupt from C4/EVENT/DREADY pin */ + if (!iio_device_claim_buffer_mode(indio_dev)) { + ade9000_iio_push_buffer(indio_dev); + iio_device_release_buffer_mode(indio_dev); + } + + return IRQ_HANDLED; +} + +static int ade9000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + unsigned int measured; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + if (chan->type =3D=3D IIO_VOLTAGE) { + int period_reg; + int period; + + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + period_reg =3D ADE9000_REG_APERIOD; + break; + case ADE9000_PHASE_B_NR: + period_reg =3D ADE9000_REG_BPERIOD; + break; + case ADE9000_PHASE_C_NR: + period_reg =3D ADE9000_REG_CPERIOD; + break; + default: + return -EINVAL; + } + ret =3D regmap_read(st->regmap, period_reg, &period); + if (ret) + return ret; + /* + * Frequency =3D (4MHz * 65536) / (PERIOD + 1) + * 4MHz =3D ADC sample rate, 65536 =3D 2^16 period register scaling + * See ADE9000 datasheet section on period measurement + */ + *val =3D 4000 * 65536; + *val2 =3D period + 1; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; + case IIO_CHAN_INFO_RAW: + if (chan->type =3D=3D IIO_ENERGY) { + u16 lo_reg =3D chan->address; + + ret =3D regmap_bulk_read(st->regmap, lo_reg, + st->bulk_read_buf, 2); + if (ret) + return ret; + + *val =3D st->bulk_read_buf[0]; /* Lower 32 bits */ + *val2 =3D st->bulk_read_buf[1]; /* Upper 32 bits */ + return IIO_VAL_INT_64; + } + + ret =3D iio_device_claim_direct(indio_dev); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, chan->address, &measured); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + *val =3D measured; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_POWERFACTOR: + ret =3D iio_device_claim_direct(indio_dev); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, chan->address, &measured); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + *val =3D measured; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_CURRENT: + case IIO_VOLTAGE: + case IIO_ALTVOLTAGE: + case IIO_ALTCURRENT: + switch (chan->address) { + case ADE9000_REG_AI_PCF: + case ADE9000_REG_AV_PCF: + case ADE9000_REG_BI_PCF: + case ADE9000_REG_BV_PCF: + case ADE9000_REG_CI_PCF: + case ADE9000_REG_CV_PCF: + *val =3D 1; + *val2 =3D ADE9000_PCF_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + case ADE9000_REG_AIRMS: + case ADE9000_REG_AVRMS: + case ADE9000_REG_BIRMS: + case ADE9000_REG_BVRMS: + case ADE9000_REG_CIRMS: + case ADE9000_REG_CVRMS: + *val =3D 1; + *val2 =3D ADE9000_RMS_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_POWER: + *val =3D 1; + *val2 =3D ADE9000_WATT_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + default: + break; + } + + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ade9000_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 tmp; + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_CURRENT: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMSOS, + chan->channel), val); + case IIO_VOLTAGE: + case IIO_ALTVOLTAGE: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMSOS, + chan->channel), val); + case IIO_POWER: + tmp =3D chan->address; + tmp &=3D ~ADE9000_PHASE_B_POS_BIT; + tmp &=3D ~ADE9000_PHASE_C_POS_BIT; + + switch (tmp) { + case ADE9000_REG_AWATTOS: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS, + chan->channel), val); + case ADE9000_REG_AVAR: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AVAROS, + chan->channel), val); + case ADE9000_REG_AFVAR: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AFVAROS, + chan->channel), val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBSCALE: + /* + * Calibration gain registers for fine-tuning measurements. + * These are separate from PGA gain and applied in the digital domain. + */ + switch (chan->type) { + case IIO_CURRENT: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AIGAIN, + chan->channel), val); + case IIO_VOLTAGE: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AVGAIN, + chan->channel), val); + case IIO_POWER: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_APGAIN, + chan->channel), val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + /* Per-channel scales are read-only */ + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ade9000_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int tx_val, + unsigned int *rx_val) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + + if (rx_val) + return regmap_read(st->regmap, reg, rx_val); + + return regmap_write(st->regmap, reg, tx_val); +} + +static int ade9000_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 interrupts1; + int ret; + + /* All events use MASK1 register */ + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts1); + if (ret) + return ret; + + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + if (chan->type =3D=3D IIO_VOLTAGE && dir =3D=3D IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXVA_BIT); + else if (chan->type =3D=3D IIO_CURRENT && dir =3D=3D IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXIA_BIT); + else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_RISIN= G) + return !!(interrupts1 & ADE9000_ST1_SWELLA_BIT); + else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_FALLI= NG) + return !!(interrupts1 & ADE9000_ST1_DIPA_BIT); + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or directi= on %d for phase A\n", chan->type, dir); + return -EINVAL; + case ADE9000_PHASE_B_NR: + if (chan->type =3D=3D IIO_VOLTAGE && dir =3D=3D IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXVB_BIT); + else if (chan->type =3D=3D IIO_CURRENT && dir =3D=3D IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXIB_BIT); + else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_RISIN= G) + return !!(interrupts1 & ADE9000_ST1_SWELLB_BIT); + else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_FALLI= NG) + return !!(interrupts1 & ADE9000_ST1_DIPB_BIT); + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or directi= on %d for phase B\n", chan->type, dir); + return -EINVAL; + case ADE9000_PHASE_C_NR: + if (chan->type =3D=3D IIO_VOLTAGE && dir =3D=3D IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXVC_BIT); + else if (chan->type =3D=3D IIO_CURRENT && dir =3D=3D IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXIC_BIT); + else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_RISIN= G) + return !!(interrupts1 & ADE9000_ST1_SWELLC_BIT); + else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_FALLI= NG) + return !!(interrupts1 & ADE9000_ST1_DIPC_BIT); + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or directi= on %d for phase C\n", chan->type, dir); + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ade9000_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 bit_mask; + int ret; + + /* Clear all pending events in STATUS1 register (write 1 to clear) */ + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS1, GENMASK(31, 0)); + if (ret) + return ret; + + /* Determine which interrupt bit to enable/disable */ + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + if (chan->type =3D=3D IIO_VOLTAGE && dir =3D=3D IIO_EV_DIR_EITHER) { + bit_mask =3D ADE9000_ST1_ZXVA_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_ZXVA_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_ZXVA_BIT; + } else if (chan->type =3D=3D IIO_CURRENT && dir =3D=3D IIO_EV_DIR_EITHER= ) { + bit_mask =3D ADE9000_ST1_ZXIA_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_ZXIA_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_ZXIA_BIT; + } else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_RIS= ING) { + bit_mask =3D ADE9000_ST1_SWELLA_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_SWELL_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_SWELL_BIT; + } else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_FAL= LING) { + bit_mask =3D ADE9000_ST1_DIPA_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_DIP_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_DIP_BIT; + } else { + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or direct= ion %d for phase A\n", + chan->type, dir); + return -EINVAL; + } + break; + case ADE9000_PHASE_B_NR: + if (chan->type =3D=3D IIO_VOLTAGE && dir =3D=3D IIO_EV_DIR_EITHER) { + bit_mask =3D ADE9000_ST1_ZXVB_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_ZXVB_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_ZXVB_BIT; + } else if (chan->type =3D=3D IIO_CURRENT && dir =3D=3D IIO_EV_DIR_EITHER= ) { + bit_mask =3D ADE9000_ST1_ZXIB_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_ZXIB_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_ZXIB_BIT; + } else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_RIS= ING) { + bit_mask =3D ADE9000_ST1_SWELLB_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_SWELL_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_SWELL_BIT; + } else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_FAL= LING) { + bit_mask =3D ADE9000_ST1_DIPB_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_DIP_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_DIP_BIT; + } else { + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or direct= ion %d for phase B\n", + chan->type, dir); + return -EINVAL; + } + break; + case ADE9000_PHASE_C_NR: + if (chan->type =3D=3D IIO_VOLTAGE && dir =3D=3D IIO_EV_DIR_EITHER) { + bit_mask =3D ADE9000_ST1_ZXVC_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_ZXVC_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_ZXVC_BIT; + } else if (chan->type =3D=3D IIO_CURRENT && dir =3D=3D IIO_EV_DIR_EITHER= ) { + bit_mask =3D ADE9000_ST1_ZXIC_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_ZXIC_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_ZXIC_BIT; + } else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_RIS= ING) { + bit_mask =3D ADE9000_ST1_SWELLC_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_SWELL_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_SWELL_BIT; + } else if (chan->type =3D=3D IIO_ALTVOLTAGE && dir =3D=3D IIO_EV_DIR_FAL= LING) { + bit_mask =3D ADE9000_ST1_DIPC_BIT; + if (state) + st->wfb_trg |=3D ADE9000_WFB_TRG_DIP_BIT; + else + st->wfb_trg &=3D ~ADE9000_WFB_TRG_DIP_BIT; + } else { + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or direct= ion %d for phase C\n", + chan->type, dir); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + /* Set bits if enabling event, clear bits if disabling */ + return regmap_assign_bits(st->regmap, ADE9000_REG_MASK1, bit_mask, state = ? bit_mask : 0); +} + +static int ade9000_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_FALLING: + return regmap_write(st->regmap, ADE9000_REG_DIP_LVL, val); + case IIO_EV_DIR_RISING: + return regmap_write(st->regmap, ADE9000_REG_SWELL_LVL, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ade9000_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + unsigned int data; + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_FALLING: + ret =3D regmap_read(st->regmap, ADE9000_REG_DIP_LVL, &data); + if (ret) + return ret; + *val =3D data; + return IIO_VAL_INT; + case IIO_EV_DIR_RISING: + ret =3D regmap_read(st->regmap, ADE9000_REG_SWELL_LVL, &data); + if (ret) + return ret; + *val =3D data; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ade9000_waveform_buffer_config(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 wfb_cfg_val; + u32 active_scans; + + bitmap_to_arr32(&active_scans, indio_dev->active_scan_mask, + indio_dev->masklength); + + switch (active_scans) { + case ADE9000_SCAN_POS_IA | ADE9000_SCAN_POS_VA: + wfb_cfg_val =3D ADE9000_WFB_CFG_IA_VA; + st->wfb_nr_activ_chan =3D 2; + break; + case ADE9000_SCAN_POS_IB | ADE9000_SCAN_POS_VB: + wfb_cfg_val =3D ADE9000_WFB_CFG_IB_VB; + st->wfb_nr_activ_chan =3D 2; + break; + case ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC: + wfb_cfg_val =3D ADE9000_WFB_CFG_IC_VC; + st->wfb_nr_activ_chan =3D 2; + break; + case ADE9000_SCAN_POS_IA: + wfb_cfg_val =3D ADE9000_WFB_CFG_IA; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_VA: + wfb_cfg_val =3D ADE9000_WFB_CFG_VA; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_IB: + wfb_cfg_val =3D ADE9000_WFB_CFG_IB; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_VB: + wfb_cfg_val =3D ADE9000_WFB_CFG_VB; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_IC: + wfb_cfg_val =3D ADE9000_WFB_CFG_IC; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_VC: + wfb_cfg_val =3D ADE9000_WFB_CFG_VC; + st->wfb_nr_activ_chan =3D 1; + break; + case (ADE9000_SCAN_POS_IA | ADE9000_SCAN_POS_VA | ADE9000_SCAN_POS_IB | + ADE9000_SCAN_POS_VB | ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC): + wfb_cfg_val =3D ADE9000_WFB_CFG_ALL_CHAN; + st->wfb_nr_activ_chan =3D 6; + break; + default: + dev_err(&st->spi->dev, "Unsupported combination of scans\n"); + return -EINVAL; + } + + wfb_cfg_val |=3D FIELD_PREP(ADE9000_WF_SRC_MASK, st->wf_src); + + return regmap_write(st->regmap, ADE9000_REG_WFB_CFG, wfb_cfg_val); +} + +static int ade9000_waveform_buffer_interrupt_setup(struct ade9000_state *s= t) +{ + int ret; + + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0); + if (ret) + return ret; + + /* Always use streaming mode setup */ + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); + if (ret) + return ret; + + return regmap_set_bits(st->regmap, ADE9000_REG_MASK0, + ADE9000_ST0_PAGE_FULL_BIT); +} + +static int ade9000_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + int ret; + + ret =3D ade9000_waveform_buffer_config(indio_dev); + if (ret) + return ret; + + st->wfb_nr_samples =3D ADE9000_WFB_MAX_SAMPLES_CHAN * st->wfb_nr_activ_ch= an; + + ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); + + ret =3D ade9000_waveform_buffer_interrupt_setup(st); + if (ret) + return ret; + + ret =3D regmap_set_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK); + if (ret) { + dev_err(&st->spi->dev, "Post-enable waveform buffer enable fail\n"); + return ret; + } + + return 0; +} + +static int ade9000_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + struct device *dev =3D &st->spi->dev; + u32 interrupts; + int ret; + + ret =3D regmap_clear_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK); + if (ret) { + dev_err(dev, "Post-disable waveform buffer disable fail\n"); + return ret; + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0); + if (ret) + return ret; + + interrupts =3D ADE9000_ST0_WFB_TRIG_BIT | ADE9000_ST0_PAGE_FULL_BIT; + + ret =3D regmap_clear_bits(st->regmap, ADE9000_REG_MASK0, interrupts); + if (ret) { + dev_err(dev, "Post-disable update maks0 fail\n"); + return ret; + } + + return regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); +} + +static const struct iio_buffer_setup_ops ade9000_buffer_ops =3D { + .preenable =3D &ade9000_buffer_preenable, + .postdisable =3D &ade9000_buffer_postdisable, +}; + +static int ade9000_reset(struct ade9000_state *st) +{ + struct device *dev =3D &st->spi->dev; + struct gpio_desc *gpio_reset; + int ret; + + gpio_reset =3D devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio_reset)) + return PTR_ERR(gpio_reset); + + /* Software reset via register if no GPIO available */ + if (!gpio_reset) { + ret =3D regmap_set_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_SWRST_BIT); + if (ret) + return ret; + fsleep(90); + return 0; + } + + /* Hardware reset via GPIO */ + fsleep(10); + gpiod_set_value_cansleep(gpio_reset, 0); + fsleep(50000); + + /* Only wait for completion if IRQ1 is available to signal reset done */ + if (fwnode_irq_get_byname(dev_fwnode(dev), "irq1") >=3D 0) { + if (!wait_for_completion_timeout(&st->reset_completion, + msecs_to_jiffies(1000))) { + dev_err(dev, "Reset timeout after 1s\n"); + return -ETIMEDOUT; + } + } + /* If no IRQ available, reset is already complete after the 50ms delay ab= ove */ + + return 0; +} + +static int ade9000_setup(struct ade9000_state *st) +{ + struct device *dev =3D &st->spi->dev; + int ret; + + ret =3D regmap_multi_reg_write(st->regmap, ade9000_initialization_sequenc= e, + ARRAY_SIZE(ade9000_initialization_sequence)); + if (ret) + return dev_err_probe(dev, ret, "Failed to write register sequence"); + + fsleep(2000); + + return 0; +} + +static const struct iio_info ade9000_info =3D { + .read_raw =3D ade9000_read_raw, + .write_raw =3D ade9000_write_raw, + .debugfs_reg_access =3D ade9000_reg_access, + .write_event_config =3D ade9000_write_event_config, + .read_event_config =3D ade9000_read_event_config, + .write_event_value =3D ade9000_write_event_value, + .read_event_value =3D ade9000_read_event_value, +}; + +static const struct regmap_config ade9000_regmap_config =3D { + .reg_bits =3D 16, + .val_bits =3D 32, + .max_register =3D 0x6bc, + .zero_flag_mask =3D true, + .cache_type =3D REGCACHE_RBTREE, + .reg_read =3D ade9000_spi_read_reg, + .reg_write =3D ade9000_spi_write_reg, + .volatile_reg =3D ade9000_is_volatile_reg, +}; + +static int ade9000_setup_clkout(struct device *dev, struct ade9000_state *= st) +{ + struct clk_hw *clkout_hw; + int ret; + + if (!IS_ENABLED(CONFIG_COMMON_CLK)) + return 0; + + /* + * Only provide clock output when using external CMOS clock. + * When using crystal, CLKOUT is connected to crystal and shouldn't + * be used as clock provider for other devices. + */ + if (!device_property_present(dev, "#clock-cells") || !st->clkin) + return 0; + + /* CLKOUT passes through CLKIN with divider of 1 */ + clkout_hw =3D devm_clk_hw_register_divider(dev, "clkout", __clk_get_name(= st->clkin), + CLK_SET_RATE_PARENT, NULL, 0, 1, 0, NULL); + if (IS_ERR(clkout_hw)) + return dev_err_probe(dev, PTR_ERR(clkout_hw), "Failed to register clkout= "); + + ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, clkout_hw); + if (ret) + return dev_err_probe(dev, ret, "Failed to add clock provider"); + + return 0; +} + +static int ade9000_request_irq(struct device *dev, const char *name, + irq_handler_t handler, void *dev_id) +{ + int irq, ret; + + irq =3D fwnode_irq_get_byname(dev_fwnode(dev), name); + if (irq =3D=3D -EINVAL) + return 0; /* interrupts are optional */ + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get %s irq", name); + + ret =3D devm_request_threaded_irq(dev, irq, NULL, handler, + IRQF_ONESHOT, KBUILD_MODNAME, dev_id); + if (ret) + return dev_err_probe(dev, ret, "Failed to request %s irq", name); + + return 0; +} + +static int ade9000_probe(struct spi_device *spi) +{ + struct device *dev =3D &spi->dev; + struct iio_dev *indio_dev; + struct ade9000_state *st; + struct regmap *regmap; + int ret; + + indio_dev =3D devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st =3D iio_priv(indio_dev); + + regmap =3D devm_regmap_init(dev, NULL, st, &ade9000_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Unable to allocate ADE9000 r= egmap"); + + st->regmap =3D regmap; + st->spi =3D spi; + + init_completion(&st->reset_completion); + + ret =3D ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); + if (ret) + return ret; + + ret =3D ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); + if (ret) + return ret; + + ret =3D ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_d= ev); + if (ret) + return ret; + + ret =3D devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + /* External CMOS clock input (optional - crystal can be used instead) */ + st->clkin =3D devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(st->clkin)) + return dev_err_probe(dev, PTR_ERR(st->clkin), "Failed to get and enable = clkin"); + + ret =3D ade9000_setup_clkout(dev, st); + if (ret) + return ret; + + indio_dev->name =3D "ade9000"; + indio_dev->info =3D &ade9000_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; + indio_dev->setup_ops =3D &ade9000_buffer_ops; + + ret =3D devm_regulator_get_enable(&spi->dev, "vdd"); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to get and enable vdd regulator\n"); + + indio_dev->channels =3D ade9000_channels; + indio_dev->num_channels =3D ARRAY_SIZE(ade9000_channels); + + ret =3D devm_iio_kfifo_buffer_setup(dev, indio_dev, + &ade9000_buffer_ops); + if (ret) + return dev_err_probe(dev, ret, "Failed to setup IIO buffer"); + + ret =3D ade9000_reset(st); + if (ret) + return ret; + + /* Configure reference selection if vref regulator is available */ + ret =3D devm_regulator_get_enable_optional(dev, "vref"); + if (ret !=3D -ENODEV && ret >=3D 0) { + ret =3D regmap_set_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_EXT_REF_MASK); + if (ret) + return ret; + } else if (ret < 0 && ret !=3D -ENODEV) { + return dev_err_probe(dev, ret, + "Failed to get and enable vref regulator\n"); + } + + ret =3D ade9000_setup(st); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +}; + +static const struct spi_device_id ade9000_id[] =3D { + { "ade9000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ade9000_id); + +static const struct of_device_id ade9000_of_match[] =3D { + { .compatible =3D "adi,ade9000" }, + { } +}; +MODULE_DEVICE_TABLE(of, ade9000_of_match); + +static struct spi_driver ade9000_driver =3D { + .driver =3D { + .name =3D "ade9000", + .of_match_table =3D ade9000_of_match, + }, + .probe =3D ade9000_probe, + .id_table =3D ade9000_id, +}; +module_spi_driver(ade9000_driver); + +MODULE_AUTHOR("Antoniu Miclaus "); +MODULE_DESCRIPTION("Analog Devices ADE9000"); +MODULE_LICENSE("GPL"); --=20 2.43.0 From nobody Fri Oct 3 02:16:59 2025 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 871C12E7BDD; Mon, 8 Sep 2025 07:36:15 +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=1757316977; cv=none; b=LM+ecuNknykF+dpIGq+rMgSsRHcixSH77uoBZLgYtuW+RbyjiuIkP7JhsUn/NhaIQOAqBhG2Hy8bo//P8R+BMXf0bCzeRXyRBY+f7WJ17B7c21t+A3xzMTfYiT1YGR1J/WYLcOVf9Ztg6N1Dmz+9j1F+x8pNzOYyyfRmJfaxRyM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316977; c=relaxed/simple; bh=RZdypEBMSKk8qtJMq+BfweRWBMoWQdLzOlE8jdpw0mY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rVf1kOBVfOaidi6hNy2baLJ9/a72Zm8NSYo9j5vgNLOrAo5kjtIG8U3VwScz4nQasfPzVHtH6JnQ2ICNi6qfotTEYR4l4g1RHqp/ZYb+1I6FxGIDLK/sEWzZdvG/huYlp0m+QMiDmDW28gEDN+0fbsye6Jor9IP0GbTvded9xBY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none 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=rzMIgrny; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none 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="rzMIgrny" Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58863o3c019421; Mon, 8 Sep 2025 03:36:12 -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=UoZCL 5TkBS0qk2hT+xmyqWBzEwqui/66oQ1ZCv973r0=; b=rzMIgrnyUB2d/CncElLu4 mPzlN7hpM7k4mNyjghud9Jeuv6WrIe94R2M3ADUxsuJOMX6wybLGlvzjzMqWR5j2 DOJtkYcJ7CtX+Oy91Y0Qbd5W6byrrAOQHk+wB6FjEblvOsk1vJdpMS8unvRCASk1 lwvp9xqpmX+fzcbzp9YLa3TQBYPhMGCIMqS7yHNdf4LaWnuA4t3EzBidpcodIUiQ tuaNEjatBV0YqwxAnUz/E9kVjY1UihqMK3V2ThopHpn6ZjwwdJwvVLPbECWaVv+K X6PTz8x1wzR2bkR/0Gq8HLIJqAkcv+2HBGQRQ+O2PQ6htH5oZUccPc6/vBiro/jo g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 491h0m29xv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 Sep 2025 03:36:12 -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 5887aBDA036472 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 8 Sep 2025 03:36:11 -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.10; Mon, 8 Sep 2025 03:36:11 -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.10 via Frontend Transport; Mon, 8 Sep 2025 03:36:11 -0400 Received: from Ubuntu.ad.analog.com ([10.132.255.227]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 5887ZpEh004718; Mon, 8 Sep 2025 03:36:04 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v7 5/6] docs: iio: add documentation for ade9000 driver Date: Mon, 8 Sep 2025 07:35:25 +0000 Message-ID: <20250908073531.3639-6-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908073531.3639-1-antoniu.miclaus@analog.com> References: <20250908073531.3639-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-ORIG-GUID: b53jOJ34ymfK1B6A0rnuOPSNL39_Xn3j X-Proofpoint-GUID: b53jOJ34ymfK1B6A0rnuOPSNL39_Xn3j X-Authority-Analysis: v=2.4 cv=MKFgmNZl c=1 sm=1 tr=0 ts=68be876c cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=gAnH3GRIAAAA:8 a=jBZNeLu39LLBpTe4D9EA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA3MDIxMiBTYWx0ZWRfX/mwkPsfQTR34 DKE+8EfJwLYrl1STz2ZCsb2Ys9aFkNgHdAcqM//12dk1LJGDm4Ss7pj5Uasquyvz66yy3038mgt VJ0rP0718GgP1G7zP5o7wrgJ6KO5ezlDsN8KaHT8I/KxfqAlknTNb0fLguTwl/VbOCDeLzrJ6Zt 18fx4UKK/xln2RPKiE+70pGpjia7HTkiNi2QzJ2MfFgGPhwV89O0gaEn2VqVMgdBo5PFwm6R67q mYb0RpQmi75hxfFItbv/lOahTAmoSBr+3MiszTFiUGplVT9hxqFQSmD7hSDoHjN1pPWQQ29oay6 DltA47ZZcS57ZCOIWMPaJNulxjmFF7ZkVlkOruBnf44YVu0yrgSBA/MLD8lJf5jSG5D62aeyzXG /viIpF+z X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-08_02,2025-09-04_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 adultscore=0 priorityscore=1501 bulkscore=0 spamscore=0 malwarescore=0 phishscore=0 impostorscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509070212 Add documentation for ade9000 driver which describes the driver device files and shows how the user may use the ABI for various scenarios (configuration, measurement, etc.). Signed-off-by: Antoniu Miclaus --- changes in v7: - remove PGA gain documentation section - remove frequency configuration section - remove scale and frequency attributes from device-level attributes table - update examples to remove PGA gain and frequency configuration Documentation/iio/ade9000.rst | 265 ++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 266 insertions(+) create mode 100644 Documentation/iio/ade9000.rst diff --git a/Documentation/iio/ade9000.rst b/Documentation/iio/ade9000.rst new file mode 100644 index 000000000000..163d36a56be3 --- /dev/null +++ b/Documentation/iio/ade9000.rst @@ -0,0 +1,265 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +ADE9000 driver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver supports Analog Device's ADE9000 energy measurement IC on SPI = bus. + +1. Supported devices +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +* `ADE9000 `_ + +The ADE9000 is a highly accurate, fully integrated, multiphase energy and = power +quality monitoring device. Superior analog performance and a digital signal +processing (DSP) core enable accurate energy monitoring over a wide dynamic +range. An integrated high end reference ensures low drift over temperature +with a combined drift of less than =C2=B125 ppm/=C2=B0C maximum for the en= tire channel +including a programmable gain amplifier (PGA) and an analog-to-digital +converter (ADC). + +2. Device attributes +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Power and energy measurements are provided for voltage, current, active po= wer, +reactive power, apparent power, and power factor across three phases. + +Each IIO device has a device folder under ``/sys/bus/iio/devices/iio:devic= eX``, +where X is the IIO index of the device. Under these folders reside a set of +device files, depending on the characteristics and features of the hardware +device in question. These files are consistently generalized and documente= d in +the IIO ABI documentation. + +The following tables show the ADE9000 related device files, found in the +specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. + ++---------------------------------------------------+---------------------= -------------------------------------+ +| Current measurement related device files | Description = | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_current[0-2]_raw | Raw current measurem= ent for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_current[0-2]_scale | Scale for current ch= annels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_current[0-2]_calibscale | Calibration gain for= current channels (AIGAIN reg). | +| in_altcurrent[0-2]_rms_raw | RMS current measurem= ent for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altcurrent[0-2]_rms_scale | Scale for RMS curren= t channels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altcurrent[0-2]_rms_calibbias | RMS offset correctio= n for current channels (IRMSOS reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++---------------------------------------------------+---------------------= -------------------------------------+ +| Voltage measurement related device files | Description = | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage[0-2]_raw | Raw voltage measurem= ent for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage[0-2]_scale | Scale for voltage ch= annels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage[0-2]_calibscale | Calibration gain for= voltage channels (AVGAIN reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage[0-2]_frequency | Measured line freque= ncy from instantaneous voltage. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_raw | RMS voltage measurem= ent for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_scale | Scale for RMS voltag= e channels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_calibbias | RMS offset correctio= n for voltage channels (VRMSOS reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++---------------------------------------------------+---------------------= -------------------------------------+ +| Power measurement related device files | Description = | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_active_raw | Active power measure= ment for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_active_scale | Scale for active pow= er channels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_active_calibbias | Calibration offset f= or active power (xWATTOS regs). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_active_calibscale | Calibration gain for= active power (APGAIN reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_reactive_raw | Reactive power measu= rement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_reactive_scale | Scale for reactive p= ower channels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_reactive_calibbias | Calibration offset f= or reactive power (xVAROS regs). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_apparent_raw | Apparent power measu= rement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_apparent_scale | Scale for apparent p= ower channels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_powerfactor | Power factor for pha= ses A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++---------------------------------------------------+---------------------= -------------------------------------+ +| Energy measurement related device files | Description = | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_energy[0-2]_active_raw | Active energy measur= ement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_energy[0-2]_reactive_raw | Reactive energy meas= urement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_energy[0-2]_apparent_raw | Apparent energy meas= urement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++------------------------------+------------------------------------------= ------------------------+ +| Shared device attributes | Description = | ++------------------------------+------------------------------------------= ------------------------+ +| name | Name of the IIO device. = | ++------------------------------+------------------------------------------= ------------------------+ +| filter_type | Waveform buffer filter type (sinc4, sinc4= +lp). | ++------------------------------+------------------------------------------= ------------------------+ +| filter_type_available | Available filter types for waveform buffe= r. | ++------------------------------+------------------------------------------= ------------------------+ + +3. Calibration and scaling +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +The ADE9000 provides multiple levels of gain and offset correction: + +**Calibration Gain (per-channel)** + Fine-tuning calibration gains applied in the digital domain for each cha= nnel type. + Controlled via ``calibscale`` attributes (AIGAIN, AVGAIN, APGAIN registe= rs). + +**Calibration Bias (per-channel)** + Hardware calibration offsets applied by the device internally: + + - Power measurements: Controlled via ``calibbias`` attributes for power = channels (xWATTOS, xVAROS registers). + - RMS measurements: Controlled via ``calibbias`` attributes for RMS chan= nels (IRMSOS, VRMSOS registers). + + These are internal chip calibrations, not userspace-applied offsets. + +4. Event attributes +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The ADE9000 provides various interrupts that are mapped to IIO events. +Event functionality is only available if the corresponding interrupts are +connected in the device tree. + ++---------------------------------------------------+---------------------= -------------------------------------+ +| IIO Event Attribute | ADE9000 Datasheet Eq= uivalent | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage[0-2]_thresh_either_en | Zero crossing detect= ion interrupt (ZXVx) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_rising_en | RMS swell detection = interrupt (SWELLx) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_rising_value | RMS swell threshold = (SWELL_LVL register) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_falling_en | RMS sag/dip detectio= n interrupt (DIPx) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_falling_value | RMS sag/dip threshol= d (DIP_LVL register) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_current[0-2]_thresh_either_en | Current zero crossin= g detection interrupt (ZXIx) | ++---------------------------------------------------+---------------------= -------------------------------------+ + +Event directions: +- ``rising``: Upper threshold crossing (swell detection) +- ``falling``: Lower threshold crossing (sag/dip detection) +- ``either``: Any threshold crossing (zero crossing detection) +- ``none``: Timeout or non-directional events + +**Note**: Event attributes are only available if the corresponding interru= pts +(irq0, irq1, dready) are specified in the device tree. The driver works wi= thout +interrupts but with reduced functionality. + +5. Device buffers +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver supports IIO buffers for waveform capture. Buffer functionality +requires the dready interrupt to be connected. + +The device supports capturing voltage and current waveforms for power qual= ity +analysis. The waveform buffer can be configured to capture data from diffe= rent +channel combinations. + +Supported channel combinations for buffered capture: +- Phase A: voltage and current (IA + VA) +- Phase B: voltage and current (IB + VB) +- Phase C: voltage and current (IC + VC) +- All phases: all voltage and current channels +- Individual channels: IA, VA, IB, VB, IC, VC + +Usage examples +-------------- + +Enable waveform capture for Phase A: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_c= urrent0_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_v= oltage0_en + +Set buffer length and enable: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 100 > buffer/length + root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable + +6. Clock output +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The ADE9000 can provide a clock output via the CLKOUT pin when using an ex= ternal +crystal/clock source. This feature is enabled by specifying ``#clock-cells= =3D <0>`` +in the device tree. The output clock will be registered as "clkout" and ca= n be +referenced by other devices. + +7. Usage examples +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Show device name: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat name + ade9000 + +Read voltage measurements: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_voltage0_raw + 12345 + root:/sys/bus/iio/devices/iio:device0> cat in_voltage0_scale + 0.000030517 + +- Phase A voltage =3D in_voltage0_raw * in_voltage0_scale =3D 0.3769 V + +Read power measurements: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_power0_active_raw + 5678 + root:/sys/bus/iio/devices/iio:device0> cat in_power0_scale + 0.000244140 + +- Phase A active power =3D in_power0_active_raw * in_power0_scale =3D 1.38= 6 W + +Configure calibration gains: + +.. code-block:: bash + + # Set current channel 0 calibration gain + root:/sys/bus/iio/devices/iio:device0> echo 0x800000 > in_current0= _calibscale + # Set voltage channel 0 calibration gain + root:/sys/bus/iio/devices/iio:device0> echo 0x7FFFFF > in_voltage0= _calibscale + +Configure RMS voltage event thresholds (requires interrupts): + +.. code-block:: bash + + # Set RMS sag detection threshold + root:/sys/bus/iio/devices/iio:device0> echo 180000 > events/in_alt= voltage0_rms_thresh_falling_value + # Enable RMS sag detection + root:/sys/bus/iio/devices/iio:device0> echo 1 > events/in_altvolta= ge0_rms_thresh_falling_en + + # Set RMS swell detection threshold + root:/sys/bus/iio/devices/iio:device0> echo 260000 > events/in_alt= voltage0_rms_thresh_rising_value + # Enable RMS swell detection + root:/sys/bus/iio/devices/iio:device0> echo 1 > events/in_altvolta= ge0_rms_thresh_rising_en + +8. IIO Interfacing Tools +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +See ``Documentation/iio/iio_tools.rst`` for the description of the availab= le IIO +interfacing tools. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index c106402a91f7..792c815286f4 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -28,6 +28,7 @@ Industrial I/O Kernel Drivers ad7606 ad7625 ad7944 + ade9000 adis16475 adis16480 adis16550 --=20 2.43.0 From nobody Fri Oct 3 02:16:59 2025 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 A3E6F2EB5C8; Mon, 8 Sep 2025 07:36:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316981; cv=none; b=FbD5K5MfEatZEA64fow2DJllVlyZEYH4w78kmKOWEvkFqEsT+AnhB1dHbjs3Kk10J/jKoXUvGITxd/bOLZRSLO7Qa0+biD//VWKhuSsKcbaaTE3YxSDZO9HwQ/mU/acUTbyAf0kA2IGdLXuA72oMUPJ6ZUcXHb31E+Ct1fEMrZ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757316981; c=relaxed/simple; bh=60BogBr1K0rEb0p6emeArENNpPrsVNzSbPc40m0yfS0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GBv+fd1bO3Y1Pp9J8ctA/O5Ls3r6N/bla/MUQraoGCJOD5so4qxpa3Mv5D8nCgsj+4SavqQb6WsrO9edroabkqizhS51ztR3MEZOQbYGsGXoV7OreuCUJhUtHQEGNZj+X6ZWeNh/r8MN6NEfOr2XBjYtbtTcvBACP8bnSZ+E/H8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none 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=FiLu2V0P; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none 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="FiLu2V0P" Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58862hlF019388; Mon, 8 Sep 2025 03:36:17 -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=M3uxZ LznLdOXjQc+lA6eO8kNZUCXyqC+Y/82cvOBmUw=; b=FiLu2V0P+ZnpHiaHEDxWU XM5OHXDNUbzdUJSsliiFG7wMLQNnsM6uKdj2f4eSEhGtlNJQAwP+xUjsSK6BXqd7 XZ7ikiWc9A3PFKim/y7ps+pUzlAKH8bQpgOF1PPHPimTybq5azEQjtn2J9jlDRpj sXyWjWbGGt9Fhkj7Erfavdxeo0K+xt3ujYKDwyzmyvLTYEr2GgZQXnuYIFdOrA7X FAyauKMXIk3I1xkcL3tZt7MlW0ok6iQPsnWDvAuhefDP/a+uP66UWlvQcy74A5tS HP4+ztcAEoiFY5wxuIFv9lBWfIoz240V0O2km/qE8UqwqhDyr5b1vYqpcydlULNV g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 491h0m29y9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 Sep 2025 03:36:16 -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 5887aF4W036483 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 8 Sep 2025 03:36:15 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) 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.10; Mon, 8 Sep 2025 03:36:15 -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.10 via Frontend Transport; Mon, 8 Sep 2025 03:36:14 -0400 Received: from Ubuntu.ad.analog.com ([10.132.255.227]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 5887ZpEi004718; Mon, 8 Sep 2025 03:36:06 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v7 6/6] Documentation: ABI: iio: add sinc4+lp Date: Mon, 8 Sep 2025 07:35:26 +0000 Message-ID: <20250908073531.3639-7-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908073531.3639-1-antoniu.miclaus@analog.com> References: <20250908073531.3639-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: JHJ7KBWy_IuMbruUIjaqpUnQ90v3TGrQ X-Proofpoint-GUID: JHJ7KBWy_IuMbruUIjaqpUnQ90v3TGrQ X-Authority-Analysis: v=2.4 cv=MKFgmNZl c=1 sm=1 tr=0 ts=68be8770 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=yJojWOMRYYMA:10 a=gAnH3GRIAAAA:8 a=vk65wfBuYYdHxbUI-70A:9 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA3MDIxMiBTYWx0ZWRfX1rS/as3+CSIj SQ/BUyKtE2PrwO3V/ipcfRFz31LWxNkwPxkRKd7BOYpSRLWR7X+dQW/NHwCWUjGAmZs5gYFKjvi FxqFfw3dhunx72qeZ825cn3TOECrrD5EVFaWXBNa6lWZm6ilQ7TAEjpfBobSvGh3J8sXcxWWROO x58b1XHy5yCMLsX4+s5L1bb2g1L4rHhuEk189qHQGjSzztleNqTPSxiGa+UxnMzRYlkgZRqMSFC GP9+2o2tNBlWNt6q2V4GzgZmxQzFu4JgGHKfDrTgpjdFbXbLPPM0y+W1NyNaAycKrlGBixpApH5 YTs5k57z6Hn3BhitOguGs+2Oby/zOMWhOCJJ5pmjIayKgmHhW/C+226TJRRaW9gZELfS5G7e8Vb sdWHjdbj X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-08_02,2025-09-04_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 adultscore=0 priorityscore=1501 bulkscore=0 spamscore=0 malwarescore=0 phishscore=0 impostorscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509070212 Content-Type: text/plain; charset="utf-8" Add new filter type to the sysfs-bus-iio ABI documentation: - "sinc4+lp" for Sinc4 + Low Pass Filter Signed-off-by: Antoniu Miclaus --- no changes in v7. Documentation/ABI/testing/sysfs-bus-iio | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/te= sting/sysfs-bus-iio index 78da68826307..cb300135b4c4 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2319,6 +2319,7 @@ Description: time. * "sinc4" - Sinc 4. Excellent noise performance. Long 1st conversion time. + * "sinc4+lp" - Sinc4 + Low Pass Filter. * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion time. * "sinc5" - The digital sinc5 filter. Excellent noise --=20 2.43.0