From nobody Fri Oct 3 23:06:19 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 A4638259C80; Fri, 22 Aug 2025 16:02:32 +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=1755878554; cv=none; b=TYVeteNepXnmUM3VIIyGORu7wLVTemgZ683Unu4x55v8ENPkHbEsSLyzYVJ/YmO17eWxgYQ7R+eUqYzMZw3Kblk8NcucF7JIDcPRHdIwEyhKxHmqqyqKU8RCE6CSArQ4oUskJeu0QYlJa50Jc6glm8vmDfjr8ni+2EzDmWfxpuc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755878554; c=relaxed/simple; bh=dhOg+VZN44o+CXSOGCZv67OHgoxsMxRqLu16L7rYI6Q=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=j01K1MilJyKVkNIruOfevaY3vL+rpJb8aIwtfwcc66XWgdwxsqlr99VTD/ZAFp/YPDd6WeUN93dsGC8bN9BMoYr1RxnE7B4AlAJrfEHBIQ5J9iUENAN5vSncfxfKSIVPsE3PWChBcLzeGPL3bWyU2l9mslzO4t+zsiDHFDTEDJM= 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=uzTkGBKy; 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="uzTkGBKy" 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 57MDoLoZ023469; Fri, 22 Aug 2025 12:02:18 -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=kVPHJ wR9tC42DMZrTzZ8ZH7JOkyM9RMBG1ATWgTL+3w=; b=uzTkGBKyHuCPdb+E/tfEn 98Q9FXspC4MQY/3Vzusdr5B1TIICA/C4MJccC43w9gOblfY9E7FuTLwzGe0LLoNk BXaIt8DxsiKRt0ZTlgQAuKfqsD6FkGwe4zW3iFYn8BadWgyosRy3AcAXQUwveZYS uOat4Mre72GwrbSU7VoJ4B0NDZjNuUZZ1vCAc4GXYyURmlOfW2vL71/dFUi87k1F gtsh5JcqT7INhaU5DqlKBQuScaOaUuAMBlotKPEFWRG+XWXiO4DgUsWOcDUAWiji +BaLQxQ235iUUj7sKVACjFtB/Ed6QexNw6Vyms8kCx44DjK6yXWQDtcMeM3epQls Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 48ppn3sgkh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 22 Aug 2025 12:02:18 -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 57MG2H4G058833 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Aug 2025 12:02:17 -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; Fri, 22 Aug 2025 12:02:17 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 22 Aug 2025 12:02:17 -0400 Received: from Ubuntu.ad.analog.com ([10.32.13.98]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 57MG263M000568; Fri, 22 Aug 2025 12:02:12 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v5 1/6] iio: add IIO_ALTCURRENT channel type Date: Fri, 22 Aug 2025 16:01:50 +0000 Message-ID: <20250822160157.5092-2-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822160157.5092-1-antoniu.miclaus@analog.com> References: <20250822160157.5092-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: AW1haW4tMjUwODIyMDA5NiBTYWx0ZWRfX00UqaHPM7+Se 8ZVmPMyPW5ApkhiU7ZsyQMezL4x7WA21OskHvIOZVc5tGLV4LR2W9I/wY/mRPPJ1zwEeCcEDu+2 9Uo1aS7A9kG1BTNnD/LxbOELzowIidHTUgyfyMxP1RWZ152FFCP9Df5ulZVf6Fkb9xYpJxREson twHyckwREcWXYkP3uxR460Lc5AoU0OXmLlYslS3LLX/0EoWOt0XHwChPJ0uMDrXUFrY1H+bVbNn KKGMr5t0LJOuPHhHuxWyo2p1SB9QeNHeLKnC5G4h3bJ2lrGY8lXIgrNEQ4mWKttX8n6fgKvUclr 3ZSIDdcFtEqDxor62W/tySTau0l3kfHO6OmGjoAIAHa9fm9rD7LYmZt4sqjZkQzdG0wZlZQm+Ww pV8cd58Hqp/2VJlKp1gQk8O85ZzLGw== X-Authority-Analysis: v=2.4 cv=frWFpF4f c=1 sm=1 tr=0 ts=68a8948a cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=2OwXVqhp2XgA:10 a=gAnH3GRIAAAA:8 a=EjsUJ71QB-Y5E-vLWTcA:9 a=cPQSjfK2_nFv0Q5t_7PE:22 X-Proofpoint-GUID: P4l6vL-cm2Zx6wNZUK7tGBm2XzrXO4Dr X-Proofpoint-ORIG-GUID: P4l6vL-cm2Zx6wNZUK7tGBm2XzrXO4Dr X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-08-22_04,2025-08-20_03,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 malwarescore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2508110000 definitions=main-2508220096 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. Signed-off-by: Antoniu Miclaus --- no changes in v5. 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 23:06:19 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 9439A25B1D3; Fri, 22 Aug 2025 16:02:33 +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=1755878556; cv=none; b=mgGAJzWSi4ZzWAF8IT2jkVuh0YAyhc9kMXFxiSKm62sGMlRveAr7xvGgBR5ovgvk2lyzqG1NH/2unAdr5Oz3oCBUlhs4oAih/cFsbWBNeIEqD558O+buw7Db36IbW/4qiA/lwfZBAAnwwzLKv5SwlBulpU1c1wnSS/8NCo4ynQI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755878556; c=relaxed/simple; bh=KtKdQIvWklMRfoS3tsolr8p4OxelHxPQxzcpIuqlAvs=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oCeLGow225IUe5DFSge6+Mr8ZTsnljj1FazvatJnoGl8QI/IIjKJd8EMtLuwrpWw/NH7BmRqaDUmGk+RWZKgCoInA1RhzqWoMadw3ikiHBXjksEYOVEp18fQzhsGYlOwQ8RzUiDaJWiIwHIEEpgBOsusa1YIImjwAIdTD9T1fAU= 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=RHDZfLyU; 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="RHDZfLyU" 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 57MBxoBI019234; Fri, 22 Aug 2025 12:02:20 -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=D+dlv 7v4cuuMV5v2jiDBXW07M7uQ5VJnOSjvqJ25xrs=; b=RHDZfLyUo3LGRH9PiDXSf k4sGjzHChuoD7zGUIJkDjSIp4fcviW3Gxg0j7Lm2+aW27wIRVeaQ31EZ4YCxCP+J MTXXfvG4cG1MB6imRTGuvAh29ZIbIlj0leyxcVWiOPng3GPjvfEWJi44Wy/NO1Rt WSxRC42cMCX58UHObERlTtITgI9CJZPwXfykIR95V5YOIgBaPE6onwu3h7lvSJ0C VgAy+r4j1Iz4hqLXB4dtkT9yv0mR7i69919vrqyHg+vw1eg5KDtssIKZsnM9weFe RulvKKJnI9crzUlPnTPyUwxefQjmDC8+eIYNy8NQI+aSql4z7lOslhaKnObj7s69 Q== Received: from nwd2mta3.analog.com ([137.71.173.56]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 48nunshdxf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 22 Aug 2025 12:02:19 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta3.analog.com (8.14.7/8.14.7) with ESMTP id 57MG2I16033802 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Aug 2025 12:02:18 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) 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; Fri, 22 Aug 2025 12:02:18 -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; Fri, 22 Aug 2025 12:02:18 -0400 Received: from Ubuntu.ad.analog.com ([10.32.13.98]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 57MG263N000568; Fri, 22 Aug 2025 12:02:13 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v5 2/6] iio: add power and energy measurement modifiers Date: Fri, 22 Aug 2025 16:01:51 +0000 Message-ID: <20250822160157.5092-3-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822160157.5092-1-antoniu.miclaus@analog.com> References: <20250822160157.5092-1-antoniu.miclaus@analog.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Authority-Analysis: v=2.4 cv=e+Zfiap/ c=1 sm=1 tr=0 ts=68a8948c cx=c_pps a=PpDZqlmH/M8setHirZLBMw==:117 a=PpDZqlmH/M8setHirZLBMw==:17 a=2OwXVqhp2XgA:10 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=klP2xDLrsrBtVFqUoHYA:9 a=cPQSjfK2_nFv0Q5t_7PE:22 X-Proofpoint-ORIG-GUID: 4uWTYHVM33lxzhuzLuAg9h6TrEhmkVYK X-Proofpoint-GUID: 4uWTYHVM33lxzhuzLuAg9h6TrEhmkVYK X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwODIxMDAyNiBTYWx0ZWRfX/G8uTAzIEArI oS2mFOKEjNfSxi7YE/x9E8f+M1wWV1GjDexKXVaFOfYCVuZRpVp8IiR5QHaGl7vf3XfpDR0Qzl5 5dKdVGZ1UidfLEo92woVHgjA5rYhtSvA6utIAlrqybLt6cuOAg9MJN3rmZp5qeJgSv9RcdZ/d/k 1HZhSHyrIEQVZgkiy9mDB3vxqejbrEKOuDp1yLi3x8lrvRZpZ2ZURFaWF2dHTCnwlIQO3GGS50a wJOYhzabpUZq23gy7VCvbl+mdX2IjgWeZ0pI/KMQo19hmBWjOmmWPwKFM1OrQYLr0icZyUINp9f UX8PDqiwkEphZIl0k+nBBiAwyHOD8LU3MwCZCA17tAlRImSvIqBVgrmNghkT6IauWDdq10vDdcd J94XKGcO2ODgILW4uStUwIUFXYL7Yg== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-08-22_04,2025-08-20_03,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 priorityscore=1501 suspectscore=0 phishscore=0 bulkscore=0 clxscore=1015 spamscore=0 malwarescore=0 adultscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2508110000 definitions=main-2508210026 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 - IIO_MOD_FUND_REACTIVE: Reactive power at fundamental frequency - IIO_MOD_FACTOR: Power factor (ratio of active to apparent power) Signal quality modifiers: - IIO_MOD_RMS: Root Mean Square value These modifiers enable proper representation of power measurement devices like energy meters and power analyzers. Signed-off-by: Antoniu Miclaus --- no changes in v5. 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 ++++ 4 files changed, 39 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 { --=20 2.43.0 From nobody Fri Oct 3 23:06:19 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 8E05C265623; Fri, 22 Aug 2025 16:02:34 +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=1755878556; cv=none; b=N+IgBFsmdo/p13JWhpIKkCWqEMs7XWi1Pdl1S1u8w9wh3ycJABeA60N+WOn/Ldk2BNTzgeu12LaaGXS8TzWpaZhzE8kYHz40VsqxVbhoceYHIUtJnhHfYjZF298hVNwtlVAhnbbB9wJZ9RYZuJ14u2YHBBjuGNRYeMH+tNAMWNY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755878556; c=relaxed/simple; bh=3Zei1DSwkNPV5Faqq+HUYq0Cw6F1eArsrPw6n1WrOEQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=myyNoW7/XRZk1DIxixqTBBtY7EFWVL+XaLQvh4gmzUkPRoljLiT2I/fyhm6AWz2iWyKkAsssHT5w8jTWXr+rPgUXqwtVgKlYstWQvTxAbllc423muGLCuGtl4DoOaONdytDFQMdi8oKUSKGUXQOivCfn/+t9eGVV4PNmhraqSo4= 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=kTnc7spp; 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="kTnc7spp" 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 57METUDb023397; Fri, 22 Aug 2025 12:02:20 -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=IoVG+ PCoJbfRxP5W6PYOWAtRrn3EOMllmajznPexEnM=; b=kTnc7sppUHwJKLhTh2g50 JJHA+kOfxkPY1spMg7Ft/9QM4/ypaxaIqEzmWlDm3U9bqjHIMC7DT+7Eo6H7L7IM VW8usgME2mjHDDlAQeFZBY8TsUx4XrEAbtYWgvF5sovwb28ELGCs1L0QKVy+Q5LZ 4ZTzSAyqqWemd2DoPsRbwdgt207LoJEC0yPG6E6RyMlrQlERM7F920vQAT9IJYHO 239C51SSV8+9gWO756l/AMKNTcw3IFe2ta16yYcYCgQc+sKXcmaaQ2/Rmtp00Obb EfKesjY3Auuzx9P+CbrHC+cXAppIxp4iV1P6OlBc7jitLkaIFbI9T834qmsiT81q w== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 48ppn3sgkn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 22 Aug 2025 12:02:19 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 57MG2IKH058836 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Aug 2025 12:02:18 -0400 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 22 Aug 2025 12:02:18 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBCASHYB5.ad.analog.com (10.64.17.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 22 Aug 2025 12:02:18 -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; Fri, 22 Aug 2025 12:02:18 -0400 Received: from Ubuntu.ad.analog.com ([10.32.13.98]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 57MG263O000568; Fri, 22 Aug 2025 12:02:14 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v5 3/6] dt-bindings: iio: adc: add ade9000 Date: Fri, 22 Aug 2025 16:01:52 +0000 Message-ID: <20250822160157.5092-4-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822160157.5092-1-antoniu.miclaus@analog.com> References: <20250822160157.5092-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: AW1haW4tMjUwODIyMDA5NiBTYWx0ZWRfX9AiLSjtA5Euu OkImNmkmfpRSNLjW+jvkK8UsutEujkxUTHcA8x89TCSKxGdXsUzDBoYYT5IcaCblihrD10b04tv 0M/cZETYnwcrN4aFf5dAXAOf61tGzlhdN2d4au7hgaANbpk0VZ7rMHyUFu17XghSmy1lRUVkGFN EpoaWxhWluvyQLHANHYp209fg26bvepsQQNfNVY5D4tpUCKR+qjwgR24xFwepC9v9qmGq0EDVdw gLFRyIQpxhBAfq2Lh5mjgjB+d7tGO3GO6JpS0L7HMwdX9JbVbdrL/aUMWqqL0YhBTuNM38oAFQH upBqD3gMwnFrgAXvv2WkmeAETSJZLeosD/s+iFhk7p7rWHEcG/wtNf+XKLbhJyf5lA8NKLaCQ7y lIJ9aosr7C9EI60UzWsI7Sw7YuwQfw== X-Authority-Analysis: v=2.4 cv=frWFpF4f c=1 sm=1 tr=0 ts=68a8948b cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=2OwXVqhp2XgA:10 a=gEfo2CItAAAA:8 a=gAnH3GRIAAAA:8 a=e6fWF6wrZI94LAapaBgA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=sptkURWiP4Gy88Gu7hUp:22 a=cPQSjfK2_nFv0Q5t_7PE:22 X-Proofpoint-GUID: YCepNRAkM4sV01LD2fv9l1OjUFXDitL6 X-Proofpoint-ORIG-GUID: YCepNRAkM4sV01LD2fv9l1OjUFXDitL6 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-08-22_04,2025-08-20_03,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 malwarescore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2508110000 definitions=main-2508220096 Add devicetree bindings support for ade9000. Signed-off-by: Antoniu Miclaus --- changes in v5: - remove clock-output-names property (simplified clock output) - make interrupts, reset-gpios, and interrupt-names optional (removed from= required list) =20 - improve interrupt-names description to allow any subset of irq0, irq1, d= ready - fix typo in description ("ADE9000 s a" -> "ADE9000 is a") - fix spacing in description ("analog-to- digital" -> "analog-to-digital") - uncomment clock example in device tree example .../bindings/iio/adc/adi,ade9000.yaml | 97 +++++++++++++++++++ 1 file changed, 97 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..a1513ad41651 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml @@ -0,0 +1,97 @@ +# 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 = driver + +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: + description: Optional interrupt names. Any subset of irq0, irq1, dread= y. + 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-names: + items: + - const: clkin + + "#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>; + clock-names =3D "clkin"; + vdd-supply =3D <&vdd_reg>; + }; + }; --=20 2.43.0 From nobody Fri Oct 3 23:06:19 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 BE1082153FB; Fri, 22 Aug 2025 16:02:31 +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=1755878555; cv=none; b=H8SK7/smD7cQSzP3kbf7468YUUO926x2b7l10mHKGBtVY9y8s3PCkLHerVQXB0VJv/R7xRxHO94OsboI5608Z9xYUqkh/q6vlrc2a5Q569f97JxvWlxjZewEyQP/g2oRlqULifAm6qzqQJ4TRC28ZHZdMGXkhc8UPXX5Qf92qyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755878555; c=relaxed/simple; bh=fATPFJtWY5kvDouEIQnvuulH7/N4hP9VamaE3xVJCyM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=OlTk25+rTV2di1ycjwmJPxgRo2SibkXaG7NhWbEq/JltRwI3jhaHATvoxCB8g/lGqpLGLXdUr/xuhAeKSFGg5XM3YhCdbY1EEMvQDM04XYXs4enkDlUYq1Ndo90TOQhdRnpoYWiuwhC35G/m8s4+rAHexJO8av0FeLr4/MVn1C8= 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=AfFrVZs/; 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="AfFrVZs/" 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 57MEOHdY023401; Fri, 22 Aug 2025 12:02:26 -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=0qL4y nq0HSGcArfJrEa3IQG0eOFSn7572Z6pTln7gi0=; b=AfFrVZs/vp2FKCXm9kRbb N9RV07KB/DvRuCEjzwsulG0FGP77NgIwhz1uTV05hfY3NZ5ZlG5+9ip49Risr9a1 GeKaostwYjngiZXb4nudnmRK7jG/AXaejfjDx3jF1jZow1xC9ToKxmSpwBcb09qf mIs1+MmQUoq4xmBl0+6bkeo8B/40S4Je7lwcBSHBiy3ZX8RrjVnsq4s1wgcQJccm AmKFsENWuq4jujdBfgXk8VXeistiBsdok3mqP5Gw5+4MNER7Bk5OwzmKfy51Q8an QLzT81WlE14VSqZJOBsbO5rbOUC/3dcX84cX58k5stWRi8mQewAwagFXbsif69DO Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 48ppn3sgmd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 22 Aug 2025 12:02:24 -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 57MG2NB9058863 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Aug 2025 12:02:23 -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; Fri, 22 Aug 2025 12:02:22 -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; Fri, 22 Aug 2025 12:02:22 -0400 Received: from Ubuntu.ad.analog.com ([10.32.13.98]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 57MG263P000568; Fri, 22 Aug 2025 12:02:16 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v5 4/6] iio: adc: add ade9000 support Date: Fri, 22 Aug 2025 16:01:53 +0000 Message-ID: <20250822160157.5092-5-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822160157.5092-1-antoniu.miclaus@analog.com> References: <20250822160157.5092-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: AW1haW4tMjUwODIyMDA5NiBTYWx0ZWRfX2zY/rGM7OTgl H58NiEvBFG5xB5+yb1R2nA+/kED/+Vblmb4qPc6+bwxD9LZ9VS1UZnOy8uycv82ZNvHx1PxkD8R 5mVevJqkwXATyTQ792Dp4abqvBvwU7YsJ2fZa9aGJ+B7azw3cjDAFCqaQ5iOOslr0WXYCOU7AkL aEFgeYui9HWscWt2DgsrCeyFjwDkpOd3uSU14zTBLPXd38YkO15Cz3ZO006gTUZS0rAg1Irr4iR L007wcxgi+mZpIOGI45TDgQSSfAAX9hdTJLV9eQJEVuJi2bt5mvYTW4sZrHW12MLTkNTo7IDFe+ akOkRhR7u53KXVpz1A8KUyOJBtb0eodP561sWW87YeCfu62m2TdlS/TqjNI5F0xX37DUu0Ayz+Y zhw+b/Lmsok7t8MMHU30gKOkwsBBfw== X-Authority-Analysis: v=2.4 cv=frWFpF4f c=1 sm=1 tr=0 ts=68a89490 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=2OwXVqhp2XgA:10 a=gAnH3GRIAAAA:8 a=qmKOYGbzNOK9OFTZhCsA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=cPQSjfK2_nFv0Q5t_7PE:22 X-Proofpoint-GUID: r3-vNnZhtsBm46QNpqxCgQjO4zORidk7 X-Proofpoint-ORIG-GUID: r3-vNnZhtsBm46QNpqxCgQjO4zORidk7 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-08-22_04,2025-08-20_03,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 malwarescore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2508110000 definitions=main-2508220096 Add driver support for the ade9000. highly accurate, fully integrated, multiphase energy and power quality monitoring device. Signed-off-by: Antoniu Miclaus --- changes in v5: - replace IIO_CHAN_INFO_HARDWAREGAIN with IIO_CHAN_INFO_CALIBSCALE for gai= n registers - replace IIO_CHAN_INFO_OFFSET with IIO_CHAN_INFO_CALIBBIAS for power chan= nel calibration offsets - change IIO_CHAN_INFO_SAMP_FREQ to IIO_CHAN_INFO_FREQUENCY for line frequ= ency - add shared PGA scale and frequency configuration via info_mask_shared_by= _all - remove per-channel HARDWAREGAIN and SAMP_FREQ from voltage channels =20 - simplify power channel attributes - make interrupts optional (driver works without IRQs but with reduced fun= ctionality) - remove unnecessary parentheses from return statements with bitwise opera= tions=20 - use dev_err_probe() for consistent error handling and improve error mess= ages - add local device variables to reduce repetitive dereferencing - remove unnecessary reinit_completion() and spi_set_drvdata() calls - fix software reset to return immediately instead of waiting for completi= on - move init_completion() before IRQ setup to avoid race conditions - add devm_mutex_init() for proper mutex initialization - simplify clock output registration (use fixed "clkout" name instead of g= enerated names) - improve code clarity with comments - update frequency validation logic (50Hz/60Hz switch statement instead of= ternary) - reorganize probe function structure and variable initialization order drivers/iio/adc/Kconfig | 19 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ade9000.c | 2011 +++++++++++++++++++++++++++++++++++++ 3 files changed, 2031 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..41f766e00de0 --- /dev/null +++ b/drivers/iio/adc/ade9000.c @@ -0,0 +1,2011 @@ +// 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 +#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_RX_DEPTH 6 +#define ADE9000_TX_DEPTH 10 + +#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 + * Clear bit 8 i.e. ACCMODE=3D0x00xx for 50Hz operation + * ACCMODE=3D0x0x9x for 3Wire delta when phase B is used as reference + */ +#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_EGYRDY_INT_EN BIT(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 + +#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 clk_hw clkout_hw; + 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); + u8 tx[ADE9000_TX_DEPTH] __aligned(IIO_DMA_MINALIGN); + u8 rx[ADE9000_RX_DEPTH]; + unsigned int bulk_read_buf[2]; +}; + +static unsigned long ade9000_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + /* CLKOUT provides the same frequency as the crystal/external clock */ + return parent_rate ? parent_rate : ADE9000_DEFAULT_CLK_FREQ_HZ; +} + +static const struct clk_ops ade9000_clkout_ops =3D { + .recalc_rate =3D ade9000_clkout_recalc_rate, +}; + +static const struct iio_event_spec ade9000_events[] =3D { + { + /* Energy ready event - datasheet: EGYRDY interrupt */ + .type =3D IIO_EV_TYPE_MAG, + .dir =3D IIO_EV_DIR_NONE, /* Non-directional event */ + .mask_shared_by_all =3D BIT(IIO_EV_INFO_ENABLE), + }, + { + /* Sequence error event - datasheet: SEQERR interrupt */ + .type =3D IIO_EV_TYPE_CHANGE, + .dir =3D IIO_EV_DIR_NONE, /* Non-directional event */ + .mask_shared_by_all =3D BIT(IIO_EV_INFO_ENABLE), + }, + { + /* Threshold events - datasheet: zero crossing timeout, sag/swell */ + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_NONE, /* Timeout events (ZXTOUT register) */ + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), /* Per-channel enable */ + .mask_shared_by_all =3D BIT(IIO_EV_INFO_VALUE), /* Shared threshold valu= e */ + }, + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_EITHER, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + }, + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_RISING, /* for swell */ + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_all =3D BIT(IIO_EV_INFO_VALUE), + }, + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_FALLING, /* for dip */ + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_all =3D 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, 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_events[0], \ + .num_event_specs =3D 1, \ + .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_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ + .event_spec =3D ade9000_events, \ + .num_event_specs =3D ARRAY_SIZE(ade9000_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), \ + .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_OFFSET), \ + .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) | \ + BIT(IIO_CHAN_INFO_POWERFACTOR), \ + .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 \ +} + +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), + /* 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), + /* 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), + /* System frequency (50Hz/60Hz) and PGA gain configuration channel */ + { + .type =3D IIO_ALTVOLTAGE, + .channel =3D 0, + .indexed =3D 1, + .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_FREQUENCY) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index =3D -1 + }, +}; + +static const struct reg_sequence ade9000_reg_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_EGYRDY_INT_EN }, + { 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 }, + { 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; + u16 addr; + int ret, len; + + guard(mutex)(&st->lock); + + addr =3D FIELD_PREP(ADE9000_REG_ADDR_MASK, reg); + put_unaligned_be16(addr, st->tx); + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) { + put_unaligned_be16(val, &st->tx[2]); + len =3D 4; + } else { + put_unaligned_be32(val, &st->tx[2]); + len =3D 6; + } + + ret =3D spi_write(st->spi, st->tx, len); + 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; + 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, st->tx); + + /* 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, st->tx, 2, st->rx, 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(st->rx); + else + *val =3D get_unaligned_be32(st->rx); + + return 0; +} + +static bool ade9000_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADE9000_REG_STATUS0: + case ADE9000_REG_STATUS1: + case ADE9000_REG_MASK0: + case ADE9000_REG_MASK1: + case ADE9000_REG_WFB_PG_IRQEN: + return false; + default: + return true; + } +} + +static int 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)); + return 0; +} + +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(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(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(dev, "IRQ0 WFB write fail\n"); + return ret; + } + + ret =3D ade9000_configure_scan(indio_dev, + ADE9000_REG_WF_HALF_BUFF); + if (ret) + return ret; + } else { + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) { + dev_err(dev, "IRQ0 WFB write fail"); + return IRQ_HANDLED; + } + + ret =3D ade9000_configure_scan(indio_dev, + ADE9000_REG_WF_BUFF); + if (ret) + return ret; + } + + 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(&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; + s64 timestamp =3D iio_get_time_ns(indio_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(dev, "IRQ0 read status fail\n"); + return IRQ_HANDLED; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK0, &interrupts); + if (ret) { + dev_err(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(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(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(dev, "IRQ0 IIO push fail @ WFB TRIG\n"); + return IRQ_HANDLED; + } + } + + handled_irq |=3D ADE9000_ST0_WFB_TRIG_BIT; + } + + if ((status & ADE9000_ST0_EGYRDY) && + (interrupts & ADE9000_ST0_EGYRDY)) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ENERGY, + ADE9000_ST0_EGYRDY, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_NONE), + timestamp); + + handled_irq |=3D ADE9000_ST0_EGYRDY; + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS0, handled_irq); + if (ret) + dev_err(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; + u32 result; + u32 status; + u32 tmp; + unsigned long interrupt_bits; + int ret; + + if (!completion_done(&st->reset_completion)) { + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS1, &result); + if (ret) { + dev_err(&st->spi->dev, "IRQ1 read status fail\n"); + return ret; + } + + if (result & ADE9000_ST1_RSTDONE_BIT) + complete(&st->reset_completion); + else + dev_err(&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(&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(&st->spi->dev, "IRQ1 read status fail\n"); + return IRQ_HANDLED; + } + + interrupt_bits =3D interrupts; + for_each_set_bit_from(bit, &interrupt_bits, + ADE9000_ST1_CROSSING_DEPTH){ + tmp =3D status & BIT(bit); + + switch (tmp) { + case ADE9000_ST1_ZXVA_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_ZXVA_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXVA_BIT; + break; + case ADE9000_ST1_ZXTOVA_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_ZXTOVA_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXTOVA_BIT; + break; + case ADE9000_ST1_ZXIA_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + ADE9000_ST1_ZXIA_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXIA_BIT; + break; + case ADE9000_ST1_ZXVB_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_ZXVB_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXVB_BIT; + break; + case ADE9000_ST1_ZXTOVB_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_ZXTOVB_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXTOVB_BIT; + break; + case ADE9000_ST1_ZXIB_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + ADE9000_ST1_ZXIB_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXIB_BIT; + break; + case ADE9000_ST1_ZXVC_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_ZXVC_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXVC_BIT; + break; + case ADE9000_ST1_ZXTOVC_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_ZXTOVC_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXTOVC_BIT; + break; + case ADE9000_ST1_ZXIC_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + ADE9000_ST1_ZXIC_BIT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + handled_irq |=3D ADE9000_ST1_ZXIC_BIT; + break; + case ADE9000_ST1_SWELLA_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_SWELLA_BIT >> 20, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + handled_irq |=3D ADE9000_ST1_SWELLA_BIT; + break; + case ADE9000_ST1_SWELLB_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_SWELLB_BIT >> 20, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + handled_irq |=3D ADE9000_ST1_SWELLB_BIT; + break; + case ADE9000_ST1_SWELLC_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_SWELLC_BIT >> 20, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + handled_irq |=3D ADE9000_ST1_SWELLC_BIT; + break; + case ADE9000_ST1_DIPA_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_DIPA_BIT >> 20, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + handled_irq |=3D ADE9000_ST1_DIPA_BIT; + break; + case ADE9000_ST1_DIPB_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_DIPB_BIT >> 20, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + handled_irq |=3D ADE9000_ST1_DIPB_BIT; + break; + case ADE9000_ST1_DIPC_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_DIPC_BIT >> 20, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + handled_irq |=3D ADE9000_ST1_DIPC_BIT; + break; + case ADE9000_ST1_SEQERR_BIT: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + ADE9000_ST1_SEQERR_BIT >> 12, + IIO_EV_TYPE_CHANGE, + IIO_EV_DIR_NONE), + timestamp); + handled_irq |=3D ADE9000_ST1_SEQERR_BIT; + break; + default: + return IRQ_HANDLED; + } + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS1, handled_irq); + if (ret) + return ret; + + 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 reg, 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; + *val =3D 4000 * 65536; + *val2 =3D period + 1; + return IIO_VAL_FRACTIONAL; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_ACCMODE, ®); + if (ret) + return ret; + *val =3D (reg & ADE9000_ACCMODE_60HZ) ? 60 : 50; + return IIO_VAL_INT; + 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; + + /* Map power channel to corresponding power factor register */ + reg =3D ADE9000_ADDR_ADJUST(ADE9000_REG_APF, chan->channel); + ret =3D regmap_read(st->regmap, reg, &measured); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + *val =3D measured; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + if (chan->info_mask_shared_by_all) { + /* Shared PGA gain read - only for channel with shared frequency */ + ret =3D regmap_read(st->regmap, ADE9000_REG_PGA_GAIN, ®); + if (ret) + return ret; + *val =3D min(1 << ((reg >> (8 + chan->channel)) & GENMASK(1, 0)), 4); + return IIO_VAL_INT; + } else if (chan->type =3D=3D IIO_CURRENT || chan->type =3D=3D IIO_VOLTAG= E || + chan->type =3D=3D IIO_ALTVOLTAGE) { + 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; + } + } else if (chan->type =3D=3D IIO_POWER) { + *val =3D 1; + *val2 =3D ADE9000_WATT_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + } else { + return -EINVAL; + } + break; + 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 addr; + u32 tmp; + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + switch (val) { + case 50: + return regmap_write(st->regmap, ADE9000_REG_ACCMODE, + ADE9000_ACCMODE); + case 60: + return regmap_write(st->regmap, ADE9000_REG_ACCMODE, + ADE9000_ACCMODE_60HZ); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + 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); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + 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: + /* Only shared PGA scale is writable, per-channel scales are read-only */ + if (!(chan->info_mask_shared_by_all)) + return -EINVAL; + + /* + * PGA (Programmable Gain Amplifier) settings affect the analog + * input stage scaling, shared by all channels. This is different + * from the per-channel calibration gains above. + */ + if (val > 4 || val < 1 || val =3D=3D 3) + return -EINVAL; + addr =3D ADE9000_REG_PGA_GAIN; + /* + * PGA gain settings: 1x, 2x, 4x (3x not supported) + * Each channel uses 2 bits in PGA_GAIN register: + * - Channel 0: bits [9:8] + * - Channel 1: bits [11:10] + * - Channel 2: bits [13:12] + * Convert gain (1,2,4) to register value (0,1,2) using ilog2() + */ + val =3D ilog2(val) << (chan->channel * 2 + 8); + tmp =3D GENMASK(1, 0) << (chan->channel * 2 + 8); + return regmap_update_bits(st->regmap, addr, tmp, val); + 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 interrupts0, interrupts1, number; + int ret; + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK0, &interrupts0); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts1); + if (ret) + return ret; + + if (type =3D=3D IIO_EV_TYPE_MAG) + return interrupts0 & ADE9000_ST0_EGYRDY; + + if (type =3D=3D IIO_EV_TYPE_CHANGE) + return interrupts1 & ADE9000_ST1_SEQERR_BIT; + + number =3D chan->channel; + + switch (number) { + case ADE9000_PHASE_A_NR: + if (chan->type =3D=3D IIO_VOLTAGE) { + if (dir =3D=3D IIO_EV_DIR_EITHER) + return interrupts1 & ADE9000_ST1_ZXVA_BIT; + if (dir =3D=3D IIO_EV_DIR_NONE) + return interrupts1 & ADE9000_ST1_ZXTOVA_BIT; + if (dir =3D=3D IIO_EV_DIR_RISING) + return interrupts1 & ADE9000_ST1_SWELLA_BIT; + if (dir =3D=3D IIO_EV_DIR_FALLING) + return interrupts1 & ADE9000_ST1_DIPA_BIT; + } else if (chan->type =3D=3D IIO_CURRENT) { + return interrupts1 & ADE9000_ST1_ZXIA_BIT; + } + break; + case ADE9000_PHASE_B_NR: + if (chan->type =3D=3D IIO_VOLTAGE) { + if (dir =3D=3D IIO_EV_DIR_EITHER) + return interrupts1 & ADE9000_ST1_ZXVB_BIT; + if (dir =3D=3D IIO_EV_DIR_NONE) + return interrupts1 & ADE9000_ST1_ZXTOVB_BIT; + if (dir =3D=3D IIO_EV_DIR_RISING) + return interrupts1 & ADE9000_ST1_SWELLB_BIT; + if (dir =3D=3D IIO_EV_DIR_FALLING) + return interrupts1 & ADE9000_ST1_DIPB_BIT; + } else if (chan->type =3D=3D IIO_CURRENT) { + return interrupts1 & ADE9000_ST1_ZXIB_BIT; + } + break; + case ADE9000_PHASE_C_NR: + if (chan->type =3D=3D IIO_VOLTAGE) { + if (dir =3D=3D IIO_EV_DIR_EITHER) + return interrupts1 & ADE9000_ST1_ZXVC_BIT; + if (dir =3D=3D IIO_EV_DIR_NONE) + return interrupts1 & ADE9000_ST1_ZXTOVC_BIT; + if (dir =3D=3D IIO_EV_DIR_RISING) + return interrupts1 & ADE9000_ST1_SWELLC_BIT; + if (dir =3D=3D IIO_EV_DIR_FALLING) + return interrupts1 & ADE9000_ST1_DIPC_BIT; + } else if (chan->type =3D=3D IIO_CURRENT) { + return interrupts1 & ADE9000_ST1_ZXIC_BIT; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +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 interrupts, tmp; + 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; + + if (type =3D=3D IIO_EV_TYPE_MAG) { + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_STATUS0, + ADE9000_ST0_EGYRDY, ADE9000_ST0_EGYRDY); + if (ret) + return ret; + return regmap_update_bits(st->regmap, ADE9000_REG_MASK0, + ADE9000_ST0_EGYRDY, + state ? ADE9000_ST1_SEQERR_BIT : 0); + } + + if (type =3D=3D IIO_EV_TYPE_CHANGE) + return regmap_update_bits(st->regmap, ADE9000_REG_MASK1, + ADE9000_ST1_SEQERR_BIT, + state ? ADE9000_ST1_SEQERR_BIT : 0); + + if (dir =3D=3D IIO_EV_DIR_EITHER) { + static const struct { + u32 irq; + u32 wfb_trg; + } trig_arr[6] =3D { + { + .irq =3D ADE9000_ST1_ZXVA_BIT, + .wfb_trg =3D ADE9000_WFB_TRG_ZXVA_BIT + }, { + .irq =3D ADE9000_ST1_ZXIA_BIT, + .wfb_trg =3D ADE9000_WFB_TRG_ZXIA_BIT + }, { + .irq =3D ADE9000_ST1_ZXVB_BIT, + .wfb_trg =3D ADE9000_WFB_TRG_ZXVB_BIT + }, { + .irq =3D ADE9000_ST1_ZXIB_BIT, + .wfb_trg =3D ADE9000_WFB_TRG_ZXIB_BIT + }, { + .irq =3D ADE9000_ST1_ZXVC_BIT, + .wfb_trg =3D ADE9000_WFB_TRG_ZXVC_BIT + }, { + .irq =3D ADE9000_ST1_ZXIC_BIT, + .wfb_trg =3D ADE9000_WFB_TRG_ZXIC_BIT + }, + }; + if (state) { + interrupts |=3D trig_arr[chan->channel * 2 + chan->type].irq; + st->wfb_trg |=3D trig_arr[chan->channel * 2 + chan->type].wfb_trg; + } else { + interrupts &=3D ~trig_arr[chan->channel * 2 + chan->type].irq; + st->wfb_trg &=3D ~trig_arr[chan->channel * 2 + chan->type].wfb_trg; + } + } + + if (dir =3D=3D IIO_EV_DIR_NONE) { + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + tmp |=3D ADE9000_ST1_ZXTOVA_BIT; + break; + case ADE9000_PHASE_B_NR: + tmp |=3D ADE9000_ST1_ZXTOVB_BIT; + break; + case ADE9000_PHASE_C_NR: + tmp |=3D ADE9000_ST1_ZXTOVC_BIT; + break; + default: + break; + } + + if (state) + interrupts |=3D tmp; + else + interrupts &=3D ~tmp; + } else if (dir =3D=3D IIO_EV_DIR_RISING) { + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + tmp |=3D ADE9000_ST1_SWELLA_BIT; + break; + case ADE9000_PHASE_B_NR: + tmp |=3D ADE9000_ST1_SWELLB_BIT; + break; + case ADE9000_PHASE_C_NR: + tmp |=3D ADE9000_ST1_SWELLC_BIT; + break; + default: + break; + } + + if (state) { + interrupts |=3D tmp; + st->wfb_trg |=3D ADE9000_WFB_TRG_SWELL_BIT; + } else { + interrupts &=3D ~tmp; + st->wfb_trg &=3D ~ADE9000_WFB_TRG_SWELL_BIT; + } + } else if (dir =3D=3D IIO_EV_DIR_FALLING) { + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + tmp |=3D ADE9000_ST1_DIPA_BIT; + break; + case ADE9000_PHASE_B_NR: + tmp |=3D ADE9000_ST1_DIPB_BIT; + break; + case ADE9000_PHASE_C_NR: + tmp |=3D ADE9000_ST1_DIPC_BIT; + break; + default: + break; + } + + if (state) { + interrupts |=3D tmp; + st->wfb_trg |=3D ADE9000_WFB_TRG_DIP_BIT; + } else { + interrupts &=3D ~tmp; + st->wfb_trg &=3D ~ADE9000_WFB_TRG_DIP_BIT; + } + } + + return regmap_update_bits(st->regmap, ADE9000_REG_MASK1, interrupts, + interrupts); +} + +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); + case IIO_EV_DIR_NONE: + return regmap_write(st->regmap, ADE9000_REG_ZXTOUT, 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; + case IIO_EV_DIR_NONE: + ret =3D regmap_read(st->regmap, ADE9000_REG_ZXTOUT, &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 =3D 0; + 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; + + ret =3D ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); + if (ret) + return ret; + + ret =3D ade9000_waveform_buffer_interrupt_setup(st); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK, + 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_update_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK, 0); + 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_update_bits(st->regmap, ADE9000_REG_MASK0, interrupts, 0); + 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 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); + + if (gpio_reset) { + fsleep(10); + gpiod_set_value_cansleep(gpio_reset, 0); + fsleep(50000); + } else { + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_SWRST_BIT, ADE9000_SWRST_BIT); + if (ret) + return ret; + fsleep(90); + return 0; + } + + if (!wait_for_completion_timeout(&st->reset_completion, + msecs_to_jiffies(1000))) { + dev_err(dev, "Reset timeout after 1s\n"); + return -ETIMEDOUT; + } + + 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_reg_sequence, + ARRAY_SIZE(ade9000_reg_sequence)); + if (ret) + return dev_err_probe(dev, ret, "Failed to write register sequence"); + + fsleep(2000); + + /* Clear all pending status bits by writing 1s */ + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); + if (ret) + return dev_err_probe(dev, ret, "Failed to clear STATUS0"); + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS1, GENMASK(31, 0)); + if (ret) + return dev_err_probe(dev, ret, "Failed to clear STATUS1"); + + return 0; +} + +static const struct iio_buffer_setup_ops ade9000_buffer_ops =3D { + .preenable =3D &ade9000_buffer_preenable, + .postdisable =3D &ade9000_buffer_postdisable, +}; + +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, + .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_init_data clk_init =3D {}; + struct clk *clkout; + int ret; + + /* + * 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; + + clk_init.name =3D "clkout"; + clk_init.ops =3D &ade9000_clkout_ops; + clk_init.flags =3D CLK_GET_RATE_NOCACHE; + clk_init.num_parents =3D 0; + + st->clkout_hw.init =3D &clk_init; + + clkout =3D devm_clk_register(dev, &st->clkout_hw); + if (IS_ERR(clkout)) + return dev_err_probe(dev, PTR_ERR(clkout), "Failed to register clkout"); + + ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &st->clkou= t_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 < 0) + return 0; + + 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 dev_err_probe(dev, -ENOMEM, "Unable to allocate ADE9000 IIO"); + + 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, "clkin"); + 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_BUFFER_SOFTWARE; + 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"); + + ret =3D devm_regulator_get_enable_optional(dev, "vref"); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, + "Failed to get and enable vref regulator\n"); + + /* Configure reference selection based on vref regulator availability */ + if (ret !=3D -ENODEV) { + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_EXT_REF_MASK, + ADE9000_EXT_REF_MASK); + if (ret) + return ret; + } + + 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; + + 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 23:06:19 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 85CAD280014; Fri, 22 Aug 2025 16:02:35 +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=1755878558; cv=none; b=nYZ0UOJgcD5mk6qczmRcQf9aTbpv+Br2oBUGtWU/gx1fKcQ2DSldJJFr2xHKRaabVJJ8cXh5cXU74/sFD9sHHhJjCmBaaw9gKTFLjAiAJKMobb0DTQac436ZFi9fOzWC9mcHfgQ5g+Tiw4BJUK5BfbW5SWMbMeZhXc47OJa8je8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755878558; c=relaxed/simple; bh=SQbiB8uO8628rxzOTyRua8rtuPwWT9plWJGuCVe9VHo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ylh36dZm72BTKo+KEF8WJq8YzxRQIPW+cForrdjno5MQ6ntrdxCcksysnPr9XhVBuu8BI2Rl6DFQRwJBpBj2gxLctWbo4wHgCe3uVzSvoPg5tx5vUWwex+3yzJXgn17PC0FJNszR7fMWIuNnCmvnRcc9n2thHhp1FQVKRL+ZxWg= 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=PC6Y/Ye7; 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="PC6Y/Ye7" 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 57MENmHT023389; Fri, 22 Aug 2025 12:02:26 -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=fgh5F 3qIah2mCV7tWs6yuuwic/sSKDNJ77mR7gFa/Lg=; b=PC6Y/Ye7GrW1v29x9jQFL 612NpEFk/7iIwGTS0I3dtgVjYrmAb95M32iQwkvCEE3mczGASM2Xbrz4l4PJAuYb FtQG83aG//hJ56749L/nqv/7G5H9LX/+3NxTr6lkw+Z4Z40xA8YTm0j3yIKT6s5o z+mTMJYx02HPrVYEFvioidginnsyGGgy8fOZg4ImR7R/fmyYujBoEznVRQnT/vF/ sHTtM+XULyrddiAvkdSqkDyblTxD/zIefjECHEw3CCxAJuX/RkcUu+icTSEKnnFT qz9OLR/Vdr+W/mPCEwCDDW//3NPxWZn81FlZ+CZRAxaQq2FWoA8JmFZE5muTUef2 A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 48ppn3sgmk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 22 Aug 2025 12:02:26 -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 57MG2PMR058866 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Aug 2025 12:02:25 -0400 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 22 Aug 2025 12:02:25 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB5.ad.analog.com (10.64.17.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 22 Aug 2025 12:02:24 -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; Fri, 22 Aug 2025 12:02:24 -0400 Received: from Ubuntu.ad.analog.com ([10.32.13.98]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 57MG263Q000568; Fri, 22 Aug 2025 12:02:18 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v5 5/6] docs: iio: add documentation for ade9000 driver Date: Fri, 22 Aug 2025 16:01:54 +0000 Message-ID: <20250822160157.5092-6-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822160157.5092-1-antoniu.miclaus@analog.com> References: <20250822160157.5092-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: AW1haW4tMjUwODIyMDA5NiBTYWx0ZWRfXxXSo8AYQVRzq nMIs+RUGMSfgDnMMWfoqfzO3yFreWoATstmYNcVTCsp1BdFUlHZJuoBXVk+A/NBLgrFwnfIoQWQ sKhiGKbI3YrQa9/j9rw8SjE2wT+HjN9h4ce9ULHDEW4d4CAygpB/CIQ5z45g4R6yU+i+Waa3qru 3dQmOlFiNdMHHM71m4Z3BIGZjkGd+uoehmFniu5LNL76MVSf9k1TBWxdLR8nzURM6zbPfbdYUsH I8UrPVKThh+tNOdciIHNsH1mmgzpLkjJA5i1/pWbm+y/bcz+hJ6mTdt3SM5CBWU2gqNXmgUQsK2 7eTrQ3bWhRcPQgm9g8O6mhK8Y23zquD7TrbK50UT3uhluHobx8KIhpCPwJI+8yFsh+fA/XVd5xt nJKzvopAHLPU1A2NhhKhIAsGVVuN9w== X-Authority-Analysis: v=2.4 cv=frWFpF4f c=1 sm=1 tr=0 ts=68a89492 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=2OwXVqhp2XgA:10 a=gAnH3GRIAAAA:8 a=2qi_iXrO6zYP4lLD778A:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=cPQSjfK2_nFv0Q5t_7PE:22 X-Proofpoint-GUID: jeS5JDanRh8EnTzgBZtm2_NIE5rFOeys X-Proofpoint-ORIG-GUID: jeS5JDanRh8EnTzgBZtm2_NIE5rFOeys X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-08-22_04,2025-08-20_03,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 malwarescore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2508110000 definitions=main-2508220096 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 --- Documentation/iio/ade9000.rst | 286 ++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 287 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..fcb4a36c0282 --- /dev/null +++ b/Documentation/iio/ade9000.rst @@ -0,0 +1,286 @@ +.. 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_current[0-2]_offset | Offset correction fo= r current channels (IRMSOS reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altcurrent[0-2]_rms_raw | RMS current measurem= ent for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++---------------------------------------------------+---------------------= -------------------------------------+ +| 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]_offset | Offset correction fo= r voltage channels (VRMSOS reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage[0-2]_frequency | Measured line freque= ncy for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_altvoltage[0-2]_rms_raw | RMS voltage measurem= ent for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++---------------------------------------------------+---------------------= -------------------------------------+ +| Power measurement related device files | Description = | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_raw | Raw active power mea= surement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_active_raw | Active power measure= ment for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_reactive_raw | Reactive power measu= rement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_apparent_raw | Apparent power measu= rement for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_powerfactor | Power factor for pha= ses A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_scale | Scale for power chan= nels. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_calibscale | Calibration gain for= power channels (APGAIN reg). | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_power[0-2]_calibbias | Calibration offset f= or power channels (xWATTOS regs). | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++---------------------------------------------------+---------------------= -------------------------------------+ +| Energy measurement related device files | Description = | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_energy[0-2]_raw | Raw energy measureme= nt for phases A, B, C. | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_energy[0-2]_scale | Scale for energy cha= nnels. | ++---------------------------------------------------+---------------------= -------------------------------------+ + ++------------------------------+------------------------------------------= ------------------------+ +| Shared device attributes | Description = | ++------------------------------+------------------------------------------= ------------------------+ +| name | Name of the IIO device. = | ++------------------------------+------------------------------------------= ------------------------+ +| frequency | System line frequency configuration (50Hz= /60Hz). | ++------------------------------+------------------------------------------= ------------------------+ +| scale | Shared PGA gain setting (1x, 2x, 4x) affe= cting all channels. | ++------------------------------+------------------------------------------= ------------------------+ + +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: + +**PGA Gain (shared)** + The programmable gain amplifier affects the analog input stage for all c= hannels. + Controlled via the shared ``scale`` attribute with values 1, 2, or 4. + +**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 Offset (per-channel)** + Hardware calibration offsets applied by the device for power measurement= s. + Controlled via ``calibbias`` attributes for power channels. + +**Correction Offsets (per-channel)** + RMS offset corrections for current and voltage measurements. + Controlled via ``offset`` attributes (IRMSOS, VRMSOS registers). + +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_voltage0_thresh_either_en | Zero crossing detect= ion interrupt (ZXVA) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage0_thresh_rising_en | Swell detection inte= rrupt (SWELLA) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage0_thresh_falling_en | Sag/dip detection in= terrupt (DIPA) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage0_thresh_none_en | Zero crossing timeou= t interrupt (ZXTOVA) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| events_mag_none_en | Energy ready interru= pt (EGYRDY) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| events_change_none_en | Sequence error inter= rupt (SEQERR) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| events_thresh_none_value | Zero crossing timeou= t threshold (ZXTOUT register) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage0_thresh_falling_value | Sag/dip threshold (D= IP_LVL register) | ++---------------------------------------------------+---------------------= -------------------------------------+ +| in_voltage0_thresh_rising_value | Swell threshold (SWE= LL_LVL register) | ++---------------------------------------------------+---------------------= -------------------------------------+ + +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 PGA gain (affects all channels): + +.. code-block:: bash + + # Set PGA gain to 2x + root:/sys/bus/iio/devices/iio:device0> echo 2 > scale + # Read current gain setting + root:/sys/bus/iio/devices/iio:device0> cat scale + 2 + +Configure line frequency: + +.. code-block:: bash + + # Set to 60Hz operation + root:/sys/bus/iio/devices/iio:device0> echo 60 > frequency + # Read current frequency setting + root:/sys/bus/iio/devices/iio:device0> cat frequency + 60 + +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 voltage event thresholds (requires interrupts): + +.. code-block:: bash + + # Set sag detection threshold + root:/sys/bus/iio/devices/iio:device0> echo 180000 > events/in_vol= tage0_thresh_falling_value + # Enable sag detection + root:/sys/bus/iio/devices/iio:device0> echo 1 > events/in_voltage0= _thresh_falling_en + + # Set swell detection threshold + root:/sys/bus/iio/devices/iio:device0> echo 260000 > events/in_vol= tage0_thresh_rising_value + # Enable swell detection + root:/sys/bus/iio/devices/iio:device0> echo 1 > events/in_voltage0= _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. \ No newline at end of file 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 23:06:19 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 9442825B1DA; Fri, 22 Aug 2025 16:02:33 +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=1755878555; cv=none; b=LxH/zgChn6X0N2ZO+dGaSmoahuFtspu3XIYA9FqLOefQSpbE4IZCa1Bcrp/xlcmR+mHadbHqJH0BbbUNupnO66+IQ4xhD2njXcPGGPzUqTzLBC+ZbHt/lZG9fXQTTZ21OPFMqD2sVJ2Qq/M/fDMoSSR4852MWeVNIhFe6HXZubE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755878555; c=relaxed/simple; bh=kspGLdPkNtzhu4rQDp5/TVNuldcYtNLHK/6wJj3wquE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Kap85PJJ4UX+xi91kmzyKpaxog79s2Jy2NrbhRWDCtyz0r3P2WgX6KAuQtf4MCPeKJa+TYG2LNJn0Br9gFX0kQ8nH1IylC3JaUccFPaf2UIOyuX+4FzgHI/LSqMARS9N7qEE3KDLRFYS2iH5DWt7fqWgvdJg4ZbzgYHyWrHG1vU= 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=SS1uCrt5; 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="SS1uCrt5" 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 57MEEmvV004396; Fri, 22 Aug 2025 12:02:25 -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=PozY+ M/LDTJ0jNL4YP/Fx/ozmIWeWf340wZY8rrkRC0=; b=SS1uCrt5Qr6jIgaUBXCqU wBlK+s4X5DkEgYUTq5wtwtDazCxyPvd+PQ0RBfwxJ4bhgPnbXbsNljFgjajgVj4E a3cGcp5RWoCLMTduRayysVJH8+PWi/IF06D73wELdjuucVHyZG2oMn6sOjgTYM9p 8J+8//H8KirXo9yaUCKT/+RHDikxL9IvoDoWeto4HIRnnFSF+uhJwi2+CAHp/AT8 Gq6qnPdl92dMwpmlBefmDaDagJQi7ELNFmr8IfzxW+PW+irkRUT6wHmh6TlAuzRO YxcZMn7zo4pKaAePTwekfDTcpU1D8giQI++t7AUlThXqU2QwgLx1ljL32mIQfy0V Q== Received: from nwd2mta3.analog.com ([137.71.173.56]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 48n0tdh4uj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 22 Aug 2025 12:02:25 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta3.analog.com (8.14.7/8.14.7) with ESMTP id 57MG2OQ2033828 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Aug 2025 12:02:24 -0400 Received: from ASHBCASHYB4.ad.analog.com (10.64.17.132) 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; Fri, 22 Aug 2025 12:02:24 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBCASHYB4.ad.analog.com (10.64.17.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 22 Aug 2025 12:02:24 -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; Fri, 22 Aug 2025 12:02:24 -0400 Received: from Ubuntu.ad.analog.com ([10.32.13.98]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 57MG263R000568; Fri, 22 Aug 2025 12:02:20 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH v5 6/6] Documentation: ABI: iio: add sinc4+lp Date: Fri, 22 Aug 2025 16:01:55 +0000 Message-ID: <20250822160157.5092-7-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822160157.5092-1-antoniu.miclaus@analog.com> References: <20250822160157.5092-1-antoniu.miclaus@analog.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Authority-Analysis: v=2.4 cv=bvAVxEai c=1 sm=1 tr=0 ts=68a89491 cx=c_pps a=PpDZqlmH/M8setHirZLBMw==:117 a=PpDZqlmH/M8setHirZLBMw==:17 a=2OwXVqhp2XgA:10 a=gAnH3GRIAAAA:8 a=U6ZNB8FNVxHzf_OyWnsA:9 a=cPQSjfK2_nFv0Q5t_7PE:22 X-Proofpoint-GUID: KcVwS01EDW1wDpRwWC4SLuRL8xH7JakT X-Proofpoint-ORIG-GUID: KcVwS01EDW1wDpRwWC4SLuRL8xH7JakT X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwODE5MDE5NSBTYWx0ZWRfX1Gyx0lGlWRJD sapyqPY+Yl6thDQ8W24we8ef3RDQcnxuSOpnHKTGAwzS369hmKebT0NvMZs1TQa9v77z5KjlxbW 76iP8mZo//1JILQIP9L/kgcCnKSsU4YPrldWotUnG2HH2nzCesNgtbnmDfnGcPYF0nMlw94+ekq RLKhKfj07vp4MiGsUElI0kxt0eiqZQIygonL8ZZbMcCHUX74MvjK3KYyIlzcr148ChSWZnVYnDj MnGkpXtErefAKwdLeK2BQguLeKihdrExiZg/7dxlNrhhaFYCZTBzw9Wt2/1Rxh9N3G0sbHR3tcV vO+jWhwiuDakmPcXEapkEJaJHLnOtGtZXSq1hJ25EZQ1lI7q2uHLVkIUZo+o9tXOS+QXPIug8vL XtMVdi/zU8PntQEeDMLjl+EK6L/IzQ== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-08-22_04,2025-08-20_03,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 impostorscore=0 clxscore=1015 lowpriorityscore=0 phishscore=0 spamscore=0 suspectscore=0 priorityscore=1501 malwarescore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2508110000 definitions=main-2508190195 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 v5. 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