From nobody Tue Oct 7 08:36:30 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 5D30D2F271F; Fri, 11 Jul 2025 18:22:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752258147; cv=none; b=H8xQkIV1aL/tgylz0VYv3aZdhIDAm3+xbD9w3u7hJdonz9qFFZcIfhl/SgGW6UOfZsI81T4yv9YFUjTGpD7SphNsuAybajwunofqRoKLJ0ahynw3jC770bMGQKv8MTlEOg38h4wWRnGDFOjlJCZ+dhokV+a5ATojsV/3t9QhzeI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752258147; c=relaxed/simple; bh=WPxqsgcHN69KaegDws1laEv2TC95EIzTRBlTXIBMEk0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CSBTqDY4LAnOYfvywkga0iZT8JyPjTsMksahni3TJ61qn86fKuaRO3r2y+G80Cpbdw4vEsAD210+7+82oUnRyXkuAWk7Dwd0b7KzZUts2xLxbbutIUTaI+J1g9IwkjlUyGtveV1jHodfycB+Xy2eAPoIx8ILOw+azAtJxUUQ1+o= 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=hlaTYecE; 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="hlaTYecE" 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 56BCIuaq004484; Fri, 11 Jul 2025 09:03:30 -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=fHYy0 eF/BH0+65Ui4ZSNiV1Q5cmY+r6R+4TLj4EVbm0=; b=hlaTYecEs1fBY8tYCqVMZ I5Yj998UKdSw36nG6ma4OSlRmU180tfkSl8vcPoiDfhtDBz2eCRnoQI11QWdyUSh x645FoqLQim0D1eRviCIlgk83Ol3F0avRVME2TB7F8/YMEnQ/GpnXBU0PVq2HLvF LOsm3qF7E93xvhpenvTBTQ6E1zV67Iq109JoRHlmQqYW62v3qRZS93wHK5x0808I BQULgfugig2oJ9RVAaK7Fdto06ASCYxAT1ZMaNA9nuQdkeGDXnLPhfXqqGKoF7gn k3+C/FstDBln7XgE2+r/Wdp0OP8lrC7Luc7iTou99KHAOLCjNkH5VoiJroodZTJA A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 47pwwa7ccd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 11 Jul 2025 09:03:30 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 56BD3TxB026792 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 11 Jul 2025 09:03:29 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBMBX8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 11 Jul 2025 09:03:29 -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, 11 Jul 2025 09:03:29 -0400 Received: from amiclaus-VirtualBox.ad.analog.com (AMICLAUS-L02.ad.analog.com [10.48.65.132]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 56BD3Jqr027484; Fri, 11 Jul 2025 09:03:25 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH 1/3] iio: add power and energy measurement modifiers Date: Fri, 11 Jul 2025 16:02:35 +0300 Message-ID: <20250711130241.159143-2-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250711130241.159143-1-antoniu.miclaus@analog.com> References: <20250711130241.159143-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: AW1haW4tMjUwNzExMDA5MiBTYWx0ZWRfX6ziA7SP9mnk+ 4gw2f53Ai/9sD3sErqM3lVr9/86zc9QDdE58mbKM2CqQxm2/a6Oh57JvyfERfbRnDl/IoQ/Jy/x MgqurWUDThvqlCmLxzO59rtcQaXoY2Ch+vZJFNnE8uOcr9vq+QKtnJFl0eFgJGf4EHkaxqbxW0Z jietsKQzz67VTgDBxTiDGbgVWcf4NSLHXISg94zNurl/sZkcWMkD38rBdpn7fKyEvFMHRfs/Ppn c6n4u7Zoo9bbD4uuJOG2FbKDakCFaS4YM2/drYWjCEHa4s6CFixMEQCWB07U1PupXuULKUQGaX0 g+GXj1ESX69O4Ywv96Mb6VhoXMv/ObGsV56csbPb07OuYbtoyq3aW5degAO30b02ihOGicXsed9 WZic52CSe9wnKrfhQLxHGSTwjYMKmacrg6QRTPIRSc08xkQH4+iwzEk96nEGqjtmu6qSqx3t X-Authority-Analysis: v=2.4 cv=E+DNpbdl c=1 sm=1 tr=0 ts=68710ba2 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=Wb1JkmetP80A:10 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=une20UNuun7GP44vQxEA:9 X-Proofpoint-GUID: B0ZDiaWG1YBaXsEPVSnMrXb5RmERYgmV X-Proofpoint-ORIG-GUID: B0ZDiaWG1YBaXsEPVSnMrXb5RmERYgmV X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.7,FMLib:17.12.80.40 definitions=2025-07-11_03,2025-07-09_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 clxscore=1015 malwarescore=0 adultscore=0 priorityscore=1501 impostorscore=0 lowpriorityscore=0 bulkscore=0 phishscore=0 classifier=spam authscore=0 authtc=n/a authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2505280000 definitions=main-2507110092 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) Energy modifiers: - IIO_MOD_ACTIVE_ACCUM: Accumulated active energy - IIO_MOD_APPARENT_ACCUM: Accumulated apparent energy - IIO_MOD_REACTIVE_ACCUM: Accumulated reactive energy Signal quality modifiers: - IIO_MOD_RMS: Root Mean Square value - IIO_MOD_SWELL: Voltage swell detection - IIO_MOD_DIP: Voltage dip (sag) detection These modifiers enable proper representation of power measurement devices like energy meters and power analyzers. Signed-off-by: Antoniu Miclaus --- Documentation/ABI/testing/sysfs-bus-iio | 19 +++++++++++++++++++ drivers/iio/industrialio-core.c | 11 +++++++++++ include/uapi/linux/iio/types.h | 11 +++++++++++ 3 files changed, 41 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/te= sting/sysfs-bus-iio index 3bc386995fb6..d5c227c03589 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -143,6 +143,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_raw What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_raw What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_raw +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_rms_raw +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_swell_raw +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_dip_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -158,6 +161,7 @@ Description: component of the signal while the 'q' channel contains the quadrature component. =20 + What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org @@ -170,6 +174,11 @@ Description: of scale and offset are millivolts. =20 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 +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_fund_reactive_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_factor_raw KernelVersion: 4.5 Contact: linux-iio@vger.kernel.org Description: @@ -178,6 +187,7 @@ 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_capacitanceY_raw KernelVersion: 3.2 Contact: linux-iio@vger.kernel.org @@ -1593,6 +1603,12 @@ 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 +What: /sys/.../iio:deviceX/in_energyY_active_accum_raw +What: /sys/.../iio:deviceX/in_energyY_reactive_accum_raw +What: /sys/.../iio:deviceX/in_energyY_apparent_accum_raw KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: @@ -1600,6 +1616,7 @@ Description: device (e.g.: human activity sensors report energy burnt by the user). Units after application of scale are Joules. =20 + What: /sys/.../iio:deviceX/in_distance_input What: /sys/.../iio:deviceX/in_distance_raw KernelVersion: 4.0 @@ -1718,6 +1735,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_currentY_r= aw What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_raw What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_raw +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_rms_raw KernelVersion: 3.17 Contact: linux-iio@vger.kernel.org Description: @@ -1733,6 +1751,7 @@ Description: component of the signal while the 'q' channel contains the quadrature component. =20 + 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 f13c3aa470d7..daf486cbe0bd 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -152,6 +152,17 @@ 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", + [IIO_MOD_FUND_REACTIVE] =3D "fund_reactive", + [IIO_MOD_FACTOR] =3D "factor", + [IIO_MOD_ACTIVE_ACCUM] =3D "active_accum", + [IIO_MOD_APPARENT_ACCUM] =3D "apparent_accum", + [IIO_MOD_REACTIVE_ACCUM] =3D "reactive_accum", + [IIO_MOD_SWELL] =3D "swell", + [IIO_MOD_DIP] =3D "dip", }; =20 /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 3eb0821af7a4..9e05bbddcbe2 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -108,6 +108,17 @@ 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, + IIO_MOD_FUND_REACTIVE, + IIO_MOD_FACTOR, + IIO_MOD_ACTIVE_ACCUM, + IIO_MOD_APPARENT_ACCUM, + IIO_MOD_REACTIVE_ACCUM, + IIO_MOD_SWELL, + IIO_MOD_DIP, }; =20 enum iio_event_type { --=20 2.49.0 From nobody Tue Oct 7 08:36:30 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 1129227E054; Fri, 11 Jul 2025 16:04:40 +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=1752249882; cv=none; b=jkJcLExzn6/8UiXgomF0PJ3Lhx6OxSleNQFSFySobo7SDu/ovkG0RGjUDsSDl3cyENmw0o4svPDQSdyeYG6qaI7vx0hW8lHmfLZnA0auklH/xUnK8maQqVeH7razuafBEzGJgsRVC9pX1BEk1CpfxSaVSlHDEYmilufIMh6v/6g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752249882; c=relaxed/simple; bh=rMPl7osvpnDKIQsHWmkHxPuALl8UmId+rqkHr1SXsII=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VsFd7+dME2DHTzONzMFeVRq55ylF33xgRy/W5z38N8Z3XqexfNXwLiZT+IT52FHBBefb5nJpAdERW3NH19bo6p7VXLcvk25q8FGCWqUO4xHEsJaaEReZ8Id+1Pl00h0zSA7Ebp68i8uj/dYGoSDcPHLFI/+kAjaiajMWy+GU3zE= 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=BIoo57Bs; 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="BIoo57Bs" 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 56BAdTI2028522; Fri, 11 Jul 2025 09:03:34 -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=MxiLn 2Dq3GFG355z0/Nng/qsnOYXFufcv0jLL3WMs8w=; b=BIoo57BsScLoD7yrIblyM AmKowQ+gkkQo3lh1FtDfN6pffX50OUITQryvPsN6ktiSMpfT+hwF4gUTD5YT0yH3 NRnOYPeo9ykUeX/j+O+kuK0KQ95T3SrBTB3eZVZ6BsSsC+10Wek3SgyS3fDOgpBf VEz7+XfMj8aKsfhK4N7ELUppj6xV/nZW405YMPgIWLhCTlRlrt2Ss5tDClRtUUJR 5jEa174EA82R2d+WW8wvOwujx+cmJEcSTxvPZxOJbbTNpwns8vl6lhCw3ORmVZ58 +rOJAUTBVpiZ0yLB3UY4+o84b4NGbz8f7q8aBKy9WfvfvKfPDvqMqRsEAVbGtQiR A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 47t67qg6mh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 11 Jul 2025 09:03:33 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 56BD3WT3026804 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 11 Jul 2025 09:03:32 -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, 11 Jul 2025 09:03:32 -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, 11 Jul 2025 09:03:32 -0400 Received: from amiclaus-VirtualBox.ad.analog.com (AMICLAUS-L02.ad.analog.com [10.48.65.132]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 56BD3Jqs027484; Fri, 11 Jul 2025 09:03:26 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH 2/3] dt-bindings: iio: adc: add ade9000 Date: Fri, 11 Jul 2025 16:02:36 +0300 Message-ID: <20250711130241.159143-3-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250711130241.159143-1-antoniu.miclaus@analog.com> References: <20250711130241.159143-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: AW1haW4tMjUwNzExMDA5MiBTYWx0ZWRfX8m0xBmwZPuPk SAhNZcj/uHxnAX7u5xLUiSX/ZhI+doDwuJLYvwSy5hfDIUca/TVf5fyxIWB8W1BmF+9rRCi6Nj1 49TeMbOlOH+F88i446pZ1MnhRKRFeP4xVCroM8YcBSTwwgslF0xb08T0+qEVWtyNBYd9VpLTzI9 pq/3s8lASpy89Jcbf+KRDR1zFySEfzvDvMX7SBDGGI2rdbyN7AYIofbtEAQxWvTrBmInHKWADFa BzhXkBQmMwwGEeVT7Cr8cnj97x84ViMQxu2CXRneBQL8SGeAz7tLL+ha561eSU0CK6PKp3FsS6E XM5Sl3hzqQaGgccBJkqdf2o2jMX1uKcPpPktSCwDJs2rczVzrC0fyYk54Sqp8Bv4ryKmMB1LIz7 Mly7/YYVOOL6Ac0UIHWH8t595YweECb9/B103zVDcJGbzyS8HRjoipX/E3f3a3zENbfLdhV3 X-Proofpoint-GUID: fxzAegytvHms1fUkbp5wsjaGm3WSFtcq X-Authority-Analysis: v=2.4 cv=eZc9f6EH c=1 sm=1 tr=0 ts=68710ba5 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Wb1JkmetP80A:10 a=gEfo2CItAAAA:8 a=gAnH3GRIAAAA:8 a=FvKjBdGZVvLRywz4negA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-ORIG-GUID: fxzAegytvHms1fUkbp5wsjaGm3WSFtcq X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.7,FMLib:17.12.80.40 definitions=2025-07-11_03,2025-07-09_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 clxscore=1015 priorityscore=1501 impostorscore=0 lowpriorityscore=4 malwarescore=0 mlxlogscore=999 phishscore=0 mlxscore=0 adultscore=0 bulkscore=4 classifier=spam authscore=0 authtc=n/a authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2505280000 definitions=main-2507110092 Add devicetree bindings support for ade9000. Signed-off-by: Antoniu Miclaus --- .../bindings/iio/adc/adi,ade9000.yaml | 157 ++++++++++++++++++ 1 file changed, 157 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..660dca4ea9b5 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml @@ -0,0 +1,157 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2025 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/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 s a highly accurate, fully integrated, multiphase energy and= 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 + +properties: + compatible: + enum: + - adi,ade9000 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + spi-max-frequency: + maximum: 20000000 + + interrupts: + maxItems: 2 + + 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 + + interrupt-names: + items: + - const: irq0 + - const: irq1 + + adi,wf-cap-en: + description: Enable fixed data rate for waveform buffer instead of res= ampled data + type: boolean + + adi,wf-mode: + description: | + Waveform buffer filling and trigger mode. + 0 - Stop when waveform buffer is full + 1 - Continuous fill, stop only on enabled trigger events + 2 - Continuous filling, center capture around enabled trigger events + 3 - Streaming mode + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + + adi,wf-src: + description: | + Waveform buffer data source selection. + 0 - Sinc4 output, at 16 kSPS + 1 - Reserved + 2 - Sinc4 + IIR LPF output, at 4 kSPS + 3 - Current and voltage channel waveform samples, processed by the D= SP at 4 kSPS + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 2, 3] + + adi,wf-in-en: + description: Enable IN waveform samples readout from waveform buffer + type: boolean + + adi,egy-time: + description: Energy accumulation time setting for energy registers + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - reg + - reset-gpios + - interrupts + - interrupt-names + - adi,wf-mode + - adi,wf-src + +additionalProperties: false + +patternProperties: + "^phase@[0-2]$": + type: object + description: | + Represents the external phases which are externally connected. Each = phase + has a current, voltage and power component + + properties: + reg: + description: | + The phase represented by a number + 0 - Phase A + 1 - Phase B + 2 - Phase C + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + required: + - reg + + additionalProperties: 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>; + + #address-cells =3D <1>; + #size-cells =3D <0>; + reset-gpios =3D <&gpio 4 GPIO_ACTIVE_LOW>; + interrupts =3D <2 IRQ_TYPE_EDGE_FALLING>, <3 IRQ_TYPE_EDGE_FAL= LING>; + interrupt-names =3D "irq0", "irq1"; + interrupt-parent =3D <&gpio>; + + adi,wf-cap-en; + adi,wf-mode =3D <3>; + adi,wf-src =3D <3>; + adi,wf-in-en; + + phase@0 { + reg =3D <0>; + }; + phase@1 { + reg =3D <1>; + }; + phase@2 { + reg =3D <2>; + }; + }; + }; +... --=20 2.49.0 From nobody Tue Oct 7 08:36:30 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 7EE28233735; Fri, 11 Jul 2025 15:12:44 +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=1752246768; cv=none; b=cJF8Iai6c8gx2dDQzV6w4xNhEzhxYU/JwhXXcvxk/E0Nl6qn34iURATiziRVQyhcSweU+Xsi62YohseY5aa3xosUh4loJw6yOkkUEaeHygpkg0qtaxAI6mMk3C0sBdMoOvJj96Pt1+SdseIFkNZ98fJsHmigxK20ZXnymniYgqs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752246768; c=relaxed/simple; bh=oUDtI4G1opiWYjE2eoy3mASEnogsejUt+eWuS5llc4Y=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hgT7Ko1xHZl9sS5zl634fI4yHvUqbhJ8naTnVVxYDlIqwru5fqmvohIdKeLcIZPLivVn0vCnOXzT+iHBBZDOXMplLvFKc9uO9jrQIYgj0lJVw9q3AlIAvyQmls53vBGqFZ/ZxkWFVCYRGhCvSlXr4HHlGPCdz6gbuizS1tpFFbc= 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=oDHz1stZ; 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="oDHz1stZ" 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 56BCIuat004484; Fri, 11 Jul 2025 09:03:36 -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=nkZxW cXAbPhSppt4jbYffjU+6YgzuoFAtdDPhLwIeTU=; b=oDHz1stZqVVqK28AMvlUo rDTjyrC4PsrtnTufBgJGTug61BbKU8VZ2Zm+rVW//mNSJPER3OpfyuALD6YSf8fQ JhYox2KOIoiHauIhGw/kvxG4nTtceOI6s6XRquLGelF0tkv/HMuyoF5/Ci3ao2es PhU+B5mcFB9vGUehHL8ffJePmkXjb3J1iyE3V6D/mheJ0sLUblfMPUZshWfKuWQj OMXzgy4JxfvHhiUTDVNyU2iktQlW3Ri6O97CbIW1/NbU+kv04TlN5xxUmJ34Eotr MukpYlUY0PScpeEUUEGlTtyX8IJoY9wAzDeO5tkRCRyBj25epWAhyTXm4JNbD5n2 Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 47pwwa7cct-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 11 Jul 2025 09:03:35 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 56BD3YR9026807 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 11 Jul 2025 09:03:34 -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, 11 Jul 2025 09:03:34 -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, 11 Jul 2025 09:03:34 -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, 11 Jul 2025 09:03:34 -0400 Received: from amiclaus-VirtualBox.ad.analog.com (AMICLAUS-L02.ad.analog.com [10.48.65.132]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 56BD3Jqt027484; Fri, 11 Jul 2025 09:03:28 -0400 From: Antoniu Miclaus To: , , , , , CC: Antoniu Miclaus Subject: [PATCH 3/3] iio: adc: add ade9000 support Date: Fri, 11 Jul 2025 16:02:37 +0300 Message-ID: <20250711130241.159143-4-antoniu.miclaus@analog.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250711130241.159143-1-antoniu.miclaus@analog.com> References: <20250711130241.159143-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: AW1haW4tMjUwNzExMDA5MiBTYWx0ZWRfX05WpY35Gi27y t2PixRjfEd6CKhwR6bm4roOUg7s1ZfMqXDaWgb1T/o2MRLuDHHFjkQ2qllhMFaPYtrg9pscZ8Mt 430VPGUdpRXiFrShTUSGZb+BWwKDhYIQVAVIAXzjcec3aEb/7p9YEl3cauxEyq1A3dw9Q93wpNk eHjlso8Tl+LZA4igdIdHKL1X/xvsPGG6Qixr0YcFr8gzWorzwbcvuBCJBcJVLT9Fga0h0hQugFV F/2ppodBIAF3Q/m7kXm67rhzUQD9FNH3Nh3jQ1WWyHsFRoa2MNsVFLGNnkxky2LfuHreVmC1CBS 7hrVjz0qMfQA6XwqZxygZ8oQtAACjmifJNpOPfs/iw3B7hf4kTJEe3Ec6WzmkrqDqT6yU1n56v4 u+rwJatAabqoP0j8VZCGnvAGcq1D3Q7o5M+kpDb3CoWVtRjh/26HuLs9kJTOhgPjE4iGNQq9 X-Authority-Analysis: v=2.4 cv=E+DNpbdl c=1 sm=1 tr=0 ts=68710ba7 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Wb1JkmetP80A:10 a=gAnH3GRIAAAA:8 a=FapeACVaOhHS9bd_UTQA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-GUID: FMbyLhSHtlMkE7MpsGyXgcbo9p6Evb43 X-Proofpoint-ORIG-GUID: FMbyLhSHtlMkE7MpsGyXgcbo9p6Evb43 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.7,FMLib:17.12.80.40 definitions=2025-07-11_03,2025-07-09_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 clxscore=1015 malwarescore=0 adultscore=0 priorityscore=1501 impostorscore=0 lowpriorityscore=0 bulkscore=0 phishscore=0 classifier=spam authscore=0 authtc=n/a authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2505280000 definitions=main-2507110092 Add driver support for the ade9000. highly accurate, fully integrated, multiphase energy and power quality monitoring device. Signed-off-by: Antoniu Miclaus --- drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 2 + drivers/iio/adc/ade9000.c | 2187 +++++++++++++++++++++++++++++++++++++ 3 files changed, 2201 insertions(+) create mode 100644 drivers/iio/adc/ade9000.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7ad58ca5173f..37dd72e4ac66 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -489,6 +489,18 @@ 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 + Support driver for the ADE9000 Multiphase Energy, and Power Quality Mon= itoring IC Driver, select y to build the driver. + + 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 15c60544a475..ed25aa838af3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_AD7091R5) +=3D ad7091r5.o obj-$(CONFIG_AD7091R8) +=3D ad7091r8.o obj-$(CONFIG_AD7124) +=3D ad7124.o obj-$(CONFIG_AD7173) +=3D ad7173.o +obj-$(CONFIG_ADE9000) +=3D ade9000.o obj-$(CONFIG_AD7191) +=3D ad7191.o obj-$(CONFIG_AD7192) +=3D ad7192.o obj-$(CONFIG_AD7266) +=3D ad7266.o @@ -45,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..4799b0bf7151 --- /dev/null +++ b/drivers/iio/adc/ade9000.c @@ -0,0 +1,2187 @@ +// 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 + +/* 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) + +/* + * Configuration registers + */ +#define ADE9000_PGA_GAIN 0x0000 + +/* Default configuration */ +#define ADE9000_CONFIG0 0x00000000 + +/* CF3/ZX pin outputs Zero crossing */ +#define ADE9000_CONFIG1 0x0002 + +//TODO: This looks like it could be better expressed in terms +//of defines for the fields contained in this register. +//Same for many of the ones that follow. + +/* 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 + +/* Disable all interrupts except EGYRDY */ +#define ADE9000_MASK0 0x00000001 + +/* Disable all interrupts */ +#define ADE9000_MASK1 0x00000000 + +/* Events disabled */ +#define ADE9000_EVENT_MASK 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_WFB_CFG 0x0329 +#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. Do not Change. + */ +#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) +#define ADE9000_SCAN_POS_ALL \ + (ADE9000_SCAN_POS_IA | \ + ADE9000_SCAN_POS_VA | \ + ADE9000_SCAN_POS_IB | \ + ADE9000_SCAN_POS_VB | \ + ADE9000_SCAN_POS_IC | \ + ADE9000_SCAN_POS_VC) + +#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 18 + +#define ADE9000_ADDR_ADJUST(addr, chan) \ + (((chan) =3D=3D 0 ? 0 : (chan) =3D=3D 1 ? 2 : 4) << 4 | (addr)) + +struct ade9000_state { + bool rst_done; + u8 wf_mode; + u32 wfb_trg; + u8 wfb_nr_activ_chan; + u32 wfb_nr_samples; + struct spi_device *spi; + u8 *tx; + u8 *rx; + u32 egy_active_accum[3]; + u32 egy_apparent_accum[3]; + u32 egy_reactive_accum[3]; + 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); +}; + +static const struct iio_event_spec ade9000_events[] =3D { + { + .type =3D IIO_EV_TYPE_MAG, + .dir =3D IIO_EV_DIR_NONE, + .mask_shared_by_all =3D BIT(IIO_EV_INFO_ENABLE), + }, + { + .type =3D IIO_EV_TYPE_CHANGE, + .dir =3D IIO_EV_DIR_NONE, + .mask_shared_by_all =3D BIT(IIO_EV_INFO_ENABLE), + }, + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_NONE, + .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_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), + }, +}; + +#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_HARDWAREGAIN), \ + .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, \ + .shift =3D 0, \ + .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_HARDWAREGAIN) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .event_spec =3D ade9000_events, \ + .num_event_specs =3D ARRAY_SIZE(ade9000_events), \ + .scan_index =3D num + 1, \ + .indexed =3D 1, \ + .scan_type =3D { \ + .sign =3D 's', \ + .realbits =3D 32, \ + .storagebits =3D 32, \ + .shift =3D 0, \ + .endianness =3D IIO_BE, \ + }, \ +} + +#define ADE9000_CURRENT_RMS_CHANNEL(num) { \ + .type =3D IIO_CURRENT, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMS, num), \ + .channel2 =3D IIO_MOD_RMS, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index =3D -1 \ +} + +#define ADE9000_VOLTAGE_RMS_CHANNEL(num) { \ + .type =3D IIO_VOLTAGE, \ + .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_OFFSET) | \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .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_OFFSET), \ + .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_POWER_FUND_REACTIVE_CHANNEL(num) { \ + .type =3D IIO_POWER, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AFVAR, num), \ + .channel2 =3D IIO_MOD_FUND_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_OFFSET), \ + .scan_index =3D -1 \ +} + +#define ADE9000_POWER_FACTOR_CHANNEL(num) { \ + .type =3D IIO_POWER, \ + .channel =3D num, \ + .address =3D ADE9000_ADDR_ADJUST(ADE9000_REG_APF, num), \ + .channel2 =3D IIO_MOD_FACTOR, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index =3D -1 \ +} + + #define ADE9000_ENERGY_ACTIVE_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_ACTIVE, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ENERGY_APPARENT_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_APPARENT, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ENERGY_REACTIVE_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_REACTIVE, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + + #define ADE9000_ENERGY_ACTIVE_ACCUM_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_ACTIVE_ACCUM, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ENERGY_APPARENT_ACCUM_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_APPARENT_ACCUM, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ENERGY_REACTIVE_ACCUM_CHANNEL(num, addr) { \ + .type =3D IIO_ENERGY, \ + .channel =3D num, \ + .address =3D addr, \ + .channel2 =3D IIO_MOD_REACTIVE_ACCUM, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_ALTVOLTAGE_ACCMODE_CHANNEL() { \ + .type =3D IIO_ALTVOLTAGE, \ + .channel =3D 0, \ + .address =3D ADE9000_REG_ACCMODE, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index =3D -1 \ +} + +#define ADE9000_VOLTAGE_SWELL_CHANNEL(num) { \ + .type =3D IIO_VOLTAGE, \ + .channel =3D num, \ + .address =3D (ADE9000_REG_SWELLA + num), \ + .channel2 =3D IIO_MOD_SWELL, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +#define ADE9000_VOLTAGE_DIP_CHANNEL(num) { \ + .type =3D IIO_VOLTAGE, \ + .channel =3D num, \ + .address =3D (ADE9000_REG_DIPA + num), \ + .channel2 =3D IIO_MOD_DIP, \ + .modified =3D 1, \ + .indexed =3D 1, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), \ + .scan_index =3D -1 \ +} + +/* IIO channels of the ade9000 for each phase individually */ +static const struct iio_chan_spec ade9000_a_channels[] =3D { + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_CURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_VOLTAGE_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_POWER_FUND_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_VOLTAGE_SWELL_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_VOLTAGE_DIP_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFVARHR_L= O), + ADE9000_ENERGY_ACTIVE_ACCUM_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATT= HR_LO), + ADE9000_ENERGY_APPARENT_ACCUM_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVA= HR_LO), + ADE9000_ENERGY_REACTIVE_ACCUM_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFV= ARHR_LO), + ADE9000_ALTVOLTAGE_ACCMODE_CHANNEL(), +}; + +static const struct iio_chan_spec ade9000_b_channels[] =3D { + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_CURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_VOLTAGE_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_POWER_FUND_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_VOLTAGE_SWELL_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_VOLTAGE_DIP_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFVARHR_L= O), + ADE9000_ENERGY_ACTIVE_ACCUM_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATT= HR_LO), + ADE9000_ENERGY_APPARENT_ACCUM_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVA= HR_LO), + ADE9000_ENERGY_REACTIVE_ACCUM_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFV= ARHR_LO), +}; + +static const struct iio_chan_spec ade9000_c_channels[] =3D { + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_CURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_VOLTAGE_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_POWER_FUND_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_VOLTAGE_SWELL_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_VOLTAGE_DIP_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFVARHR_L= O), + ADE9000_ENERGY_ACTIVE_ACCUM_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATT= HR_LO), + ADE9000_ENERGY_APPARENT_ACCUM_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVA= HR_LO), + ADE9000_ENERGY_REACTIVE_ACCUM_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFV= ARHR_LO), +}; + +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 }, + { ADE9000_REG_MASK1, ADE9000_MASK1 }, + { ADE9000_REG_EVENT_MASK, ADE9000_EVENT_MASK }, + { 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 device *dev =3D context; + struct spi_device *spi =3D to_spi_device(dev); + struct ade9000_state *st =3D spi_get_drvdata(spi); + + u16 addr; + int ret =3D 0; + struct spi_transfer xfer[] =3D { + { + .tx_buf =3D st->tx, + }, + }; + + addr =3D FIELD_PREP(ADE9000_REG_ADDR_MASK, reg); + + put_unaligned_be16(addr, st->tx); + put_unaligned_be32(val, &st->tx[2]); + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) { + put_unaligned_be16(val, &st->tx[2]); + xfer[0].len =3D 4; + } else { + xfer[0].len =3D 6; + } + + ret =3D spi_sync_transfer(st->spi, xfer, ARRAY_SIZE(xfer)); + if (ret) { + dev_err(&st->spi->dev, "problem when writing register 0x%x", + reg); + } + + return ret; +} + +static int ade9000_spi_read_reg(void *context, + unsigned int reg, + unsigned int *val) +{ + struct device *dev =3D context; + struct spi_device *spi =3D to_spi_device(dev); + struct ade9000_state *st =3D spi_get_drvdata(spi); + + u16 addr; + int ret =3D 0; + struct spi_transfer xfer[] =3D { + { + .tx_buf =3D st->tx, + .len =3D 2, + }, + { + .rx_buf =3D st->rx, + }, + }; + + addr =3D FIELD_PREP(ADE9000_REG_ADDR_MASK, reg) | + ADE9000_REG_READ_BIT_MASK; + + put_unaligned_be16(addr, st->tx); + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) + xfer[1].len =3D 4; + else + xfer[1].len =3D 6; + + ret =3D spi_sync_transfer(st->spi, xfer, ARRAY_SIZE(xfer)); + if (ret) { + dev_err(&st->spi->dev, "error reading register 0x%x", + reg); + goto err_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); + +err_ret: + return ret; +} + +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[0]; + + if (st->wf_mode =3D=3D ADE9000_WFB_STREAMING_MODE) + st->xfer[1].len =3D (st->wfb_nr_samples / 2) * 4; + else + st->xfer[1].len =3D st->wfb_nr_samples * 4; + + spi_message_init_with_transfers(&st->spi_msg, st->xfer, 2); + return 0; +} + +static int ade9000_iio_push_streaming(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 current_page; + int ret; + u32 i; + + ret =3D spi_sync(st->spi, &st->spi_msg); + if (ret) { + dev_err(&st->spi->dev, "SPI fail in trigger handler"); + return ret; + } + + 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(&st->spi->dev, "IRQ0 WFB read fail"); + 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(&st->spi->dev, "IRQ0 WFB write fail"); + 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(&st->spi->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; + + ret =3D spi_sync(st->spi, &st->spi_msg); + if (ret) { + dev_err(&st->spi->dev, "SPI fail in trigger handler"); + 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 int ade9000_en_wfb(struct ade9000_state *st, bool state) +{ + return regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG, BIT(4), + state ? BIT(4) : 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); + s64 timestamp =3D iio_get_time_ns(indio_dev); + u32 handled_irq =3D 0; + u32 interrupts; + u32 status; + int ret; + + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS0, &status); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 read status fail"); + return IRQ_HANDLED; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK0, &interrupts); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 read status fail"); + return IRQ_HANDLED; + } + + if ((status & ADE9000_ST0_PAGE_FULL_BIT) && + (interrupts & ADE9000_ST0_PAGE_FULL_BIT)) { + switch (st->wf_mode) { + case ADE9000_WFB_FULL_MODE: + ret =3D ade9000_en_wfb(st, false); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 WFB stop fail"); + return IRQ_HANDLED; + } + ret =3D ade9000_iio_push_buffer(indio_dev); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 IIO push fail"); + return IRQ_HANDLED; + } + + interrupts &=3D ~ADE9000_ST0_PAGE_FULL_BIT; + + ret =3D regmap_write(st->regmap, ADE9000_REG_MASK0, + interrupts); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 MAKS0 write fail"); + return IRQ_HANDLED; + } + break; + + case ADE9000_WFB_C_EN_TRIG_MODE: + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_LAST_PAGE_BIT); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 WFB write fail"); + return IRQ_HANDLED; + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, + st->wfb_trg); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 WFB write fail"); + return IRQ_HANDLED; + } + + interrupts |=3D ADE9000_ST0_WFB_TRIG_BIT; + interrupts &=3D ~ADE9000_ST0_PAGE_FULL_BIT; + + ret =3D regmap_write(st->regmap, ADE9000_REG_MASK0, + interrupts); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 MAKS0 write fail"); + return IRQ_HANDLED; + } + break; + + case ADE9000_WFB_EN_TRIG_MODE: + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, + st->wfb_trg); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 WFB write fail"); + return IRQ_HANDLED; + } + + interrupts |=3D ADE9000_ST0_WFB_TRIG_BIT; + + interrupts &=3D ~ADE9000_ST0_PAGE_FULL_BIT; + + ret =3D regmap_write(st->regmap, ADE9000_REG_MASK0, + interrupts); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 MAKS0 write fail"); + return IRQ_HANDLED; + } + break; + + case ADE9000_WFB_STREAMING_MODE: + ret =3D ade9000_iio_push_streaming(indio_dev); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 IIO push fail"); + return IRQ_HANDLED; + } + break; + + default: + 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 ade9000_en_wfb(st, false); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 WFB fail"); + return IRQ_HANDLED; + } + + ret =3D ade9000_iio_push_buffer(indio_dev); + if (ret) { + dev_err(&st->spi->dev, "IRQ0 IIO push fail @ WFB TRIG"); + return IRQ_HANDLED; + } + + handled_irq |=3D ADE9000_ST0_WFB_TRIG_BIT; + } + + if ((status & ADE9000_ST0_EGYRDY) && + (interrupts & ADE9000_ST0_EGYRDY)) { + u32 data; + /* As per datasheet, reading the _HI registers is enough. */ + + ret =3D regmap_read(st->regmap, (ADE9000_REG_AWATTHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_active_accum[0] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_BWATTHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_active_accum[1] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_CWATTHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_active_accum[2] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_AVAHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_apparent_accum[0] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_BVAHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_apparent_accum[1] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_CVAHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_apparent_accum[2] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_AFVARHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_reactive_accum[0] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_BFVARHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_reactive_accum[1] =3D data; + + ret =3D regmap_read(st->regmap, (ADE9000_REG_CFVARHR_LO + 1), &data); + if (ret) + return ret; + + st->egy_reactive_accum[2] =3D data; + + 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(&st->spi->dev, "IRQ0 write status fail"); + + 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; + int ret; + + if (!st->rst_done) { + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS1, &result); + if (ret) + return ret; + + if (result & ADE9000_ST1_RSTDONE_BIT) + st->rst_done =3D true; + else + dev_err(&st->spi->dev, "Error testing reset done"); + + return IRQ_HANDLED; + } + + ret =3D regmap_read(st->regmap, ADE9000_REG_STATUS1, &status); + if (ret) + return IRQ_HANDLED; + + ret =3D regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts); + if (ret) { + dev_err(&st->spi->dev, "IRQ1 read status fail"); + return IRQ_HANDLED; + } + + for_each_set_bit_from(bit, (unsigned long *)&interrupts, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 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; + int measured; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + 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 & BIT(8)) ? 60 : 50; + return IIO_VAL_INT; + case IIO_CHAN_INFO_RAW: + if (chan->type =3D=3D IIO_ENERGY && chan->modified && + chan->channel2 =3D=3D IIO_MOD_ACTIVE_ACCUM) { + *val =3D st->egy_active_accum[chan->channel]; + return IIO_VAL_INT; + } + + if (chan->type =3D=3D IIO_ENERGY && chan->modified && + chan->channel2 =3D=3D IIO_MOD_APPARENT_ACCUM) { + *val =3D st->egy_apparent_accum[chan->channel]; + return IIO_VAL_INT; + } + + if (chan->type =3D=3D IIO_ENERGY && chan->modified && + chan->channel2 =3D=3D IIO_MOD_REACTIVE_ACCUM) { + *val =3D st->egy_reactive_accum[chan->channel]; + return IIO_VAL_INT; + } + + if (chan->type =3D=3D IIO_ENERGY) { + s64 val64; + u32 data[2]; + u16 lo_reg =3D chan->address; + + ret =3D regmap_bulk_read(st->regmap, lo_reg, data, 2); + if (ret) + return ret; + + val64 =3D ((u64)data[1] << 32) | data[0]; + *(s64 *)val =3D val64; + return IIO_VAL_INT; + } + + ret =3D iio_device_claim_direct(indio_dev); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, chan->address, &measured); + if (ret) + return ret; + + iio_device_release_direct(indio_dev); + *val =3D measured; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + if (chan->type =3D=3D IIO_CURRENT || chan->type =3D=3D IIO_VOLTAGE) { + 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; + case IIO_CHAN_INFO_CALIBSCALE: + ret =3D regmap_read(st->regmap, ADE9000_REG_PGA_GAIN, ®); + if (ret) + return ret; + *val =3D 1 << ((reg >> (8 + chan->channel)) & 0x3); + if (*val > 4) + *val =3D 4; + return IIO_VAL_INT; + 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_SAMP_FREQ: + if (val !=3D 50 && val !=3D 60) + return -EINVAL; + return regmap_write(st->regmap, ADE9000_REG_ACCMODE, + (val =3D=3D 60) ? ADE9000_ACCMODE_60HZ : ADE9000_ACCMODE); + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_CURRENT: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMSOS, + chan->channel); + break; + case IIO_VOLTAGE: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMSOS, + chan->channel); + break; + 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: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS, + chan->channel); + break; + case ADE9000_REG_AVAR: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AVAROS, + chan->channel); + break; + case ADE9000_REG_AFVAR: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AFVAROS, + chan->channel); + break; + default: + return -EINVAL; + } + + break; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_HARDWAREGAIN: + switch (chan->type) { + case IIO_CURRENT: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AIGAIN, + chan->channel); + break; + case IIO_VOLTAGE: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_AVGAIN, + chan->channel); + break; + case IIO_POWER: + addr =3D ADE9000_ADDR_ADJUST(ADE9000_REG_APGAIN, + chan->channel); + break; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (val > 4 || val < 1 || val =3D=3D 3) + return -EINVAL; + addr =3D ADE9000_REG_PGA_GAIN; + val =3D ilog2(val) << (chan->channel * 2 + 8); + tmp =3D 0x3 << (chan->channel * 2 + 8); + return regmap_update_bits(st->regmap, addr, tmp, val); + default: + return -EINVAL; + } + + return regmap_write(st->regmap, addr, val); +} + +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; + struct irq_wfb_trig { + u32 irq; + u32 wfb_trg; + }; + + 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); + + struct irq_wfb_trig 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 (dir =3D=3D IIO_EV_DIR_EITHER) { + 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: + interrupts |=3D ADE9000_ST1_ZXTOVA_BIT; + break; + case ADE9000_PHASE_B_NR: + interrupts |=3D ADE9000_ST1_ZXTOVB_BIT; + break; + case ADE9000_PHASE_C_NR: + interrupts |=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_config_wfb(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 wfg_cfg_val =3D 0; + u32 active_scans; + u32 tmp; + int ret; + + 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: + wfg_cfg_val =3D 0x1; + st->wfb_nr_activ_chan =3D 2; + break; + case ADE9000_SCAN_POS_IB | ADE9000_SCAN_POS_VB: + wfg_cfg_val =3D 0x2; + st->wfb_nr_activ_chan =3D 2; + break; + case ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC: + wfg_cfg_val =3D 0x3; + st->wfb_nr_activ_chan =3D 2; + break; + case ADE9000_SCAN_POS_IA: + wfg_cfg_val =3D 0x8; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_VA: + wfg_cfg_val =3D 0x9; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_IB: + wfg_cfg_val =3D 0xA; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_VB: + wfg_cfg_val =3D 0xB; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_IC: + wfg_cfg_val =3D 0xC; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_VC: + wfg_cfg_val =3D 0xD; + st->wfb_nr_activ_chan =3D 1; + break; + case ADE9000_SCAN_POS_ALL: + wfg_cfg_val =3D 0x0; + st->wfb_nr_activ_chan =3D 6; + break; + default: + dev_err(&st->spi->dev, "Unsupported combination of scans"); + return -EINVAL; + } + + if (device_property_read_bool(&st->spi->dev, "adi,wf-cap-en")) + wfg_cfg_val |=3D FIELD_PREP(ADE9000_WF_CAP_SEL_MASK, 1); + + ret =3D device_property_read_u32(&st->spi->dev, "adi,wf-mode", &tmp); + if (ret) { + dev_err(&st->spi->dev, "Failed to get wf-mode: %d\n", ret); + return ret; + } + wfg_cfg_val |=3D FIELD_PREP(ADE9000_WF_MODE_MASK, tmp); + st->wf_mode =3D tmp; + + ret =3D device_property_read_u32(&st->spi->dev, "adi,wf-src", &tmp); + if (ret) { + dev_err(&st->spi->dev, + "Failed to get wf-src: %d\n", + ret); + return ret; + } + wfg_cfg_val |=3D FIELD_PREP(ADE9000_WF_SRC_MASK, tmp); + + if (device_property_read_bool(&st->spi->dev, "adi,wf-in-en")) + wfg_cfg_val |=3D FIELD_PREP(ADE9000_WF_IN_EN_MASK, 1); + + return regmap_write(st->regmap, ADE9000_REG_WFB_CFG, wfg_cfg_val); +} + +static int ade9000_wfb_interrupt_setup(struct ade9000_state *st, u8 mode) +{ + int ret; + + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0); + if (ret) + return ret; + + switch (mode) { + case ADE9000_WFB_FULL_MODE: + case ADE9000_WFB_EN_TRIG_MODE: + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_LAST_PAGE_BIT); + if (ret) + return ret; + break; + case ADE9000_WFB_C_EN_TRIG_MODE: + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) + return ret; + break; + case ADE9000_WFB_STREAMING_MODE: + ret =3D regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, ADE9000_REG_MASK0, + ADE9000_ST0_PAGE_FULL_BIT, + 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_config_wfb(indio_dev); + if (ret) + return ret; + + st->wfb_nr_samples =3D ADE9000_WFB_MAX_SAMPLES_CHAN * + st->wfb_nr_activ_chan; + + ret =3D ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); + if (ret) + return ret; + + ret =3D ade9000_wfb_interrupt_setup(st, st->wf_mode); + if (ret) + return ret; + + ret =3D ade9000_en_wfb(st, true); + if (ret) { + dev_err(&st->spi->dev, "Post-enable wfb enable fail"); + return ret; + } + + return 0; +} + +static int ade9000_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + u32 interrupts =3D 0; + int ret; + + ret =3D ade9000_en_wfb(st, false); + if (ret) { + dev_err(&st->spi->dev, "Post-disable wfb disable fail"); + 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; + interrupts |=3D ADE9000_ST0_PAGE_FULL_BIT; + + return regmap_update_bits(st->regmap, ADE9000_REG_MASK0, interrupts, 0); + if (ret) { + dev_err(&st->spi->dev, "Post-disable update maks0 fail"); + return ret; + } + + return regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); +} + +static int ade9000_setup_iio_channels(struct iio_dev *indio_dev) +{ + struct ade9000_state *st =3D iio_priv(indio_dev); + struct device *dev =3D &st->spi->dev; + struct fwnode_handle *phase_node =3D NULL; + struct iio_chan_spec *chan; + u32 phase_nr; + int ret; + + chan =3D devm_kcalloc(dev, + (ADE9000_MAX_PHASE_NR * + ARRAY_SIZE(ade9000_a_channels)) + 1, + sizeof(*chan), GFP_KERNEL); + if (!chan) { + dev_err(dev, "Unable to allocate ADE9000 channels"); + return -ENOMEM; + } + indio_dev->num_channels =3D 0; + indio_dev->channels =3D chan; + + struct iio_chan_spec *chan_ptr =3D chan; + + fwnode_for_each_available_child_node(dev_fwnode(dev), phase_node) { + ret =3D fwnode_property_read_u32(phase_node, "reg", &phase_nr); + if (ret) { + dev_err(dev, "Could not read channel reg : %d\n", ret); + return ret; + } + + switch (phase_nr) { + case ADE9000_PHASE_A_NR: + memcpy(chan_ptr, ade9000_a_channels, + sizeof(ade9000_a_channels)); + break; + case ADE9000_PHASE_B_NR: + memcpy(chan_ptr, ade9000_b_channels, + sizeof(ade9000_b_channels)); + break; + case ADE9000_PHASE_C_NR: + memcpy(chan_ptr, ade9000_c_channels, + sizeof(ade9000_c_channels)); + break; + default: + return -EINVAL; + } + + chan_ptr +=3D AD9000_CHANNELS_PER_PHASE; + indio_dev->num_channels +=3D AD9000_CHANNELS_PER_PHASE; + } + + return 0; +} + +static int ade9000_reset(struct ade9000_state *st) +{ + struct gpio_desc *gpio_reset; + int ret; + + st->rst_done =3D false; + + gpio_reset =3D devm_gpiod_get_optional(&st->spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(gpio_reset)) + return PTR_ERR(gpio_reset); + + if (gpio_reset) { + gpiod_set_value_cansleep(gpio_reset, 1); + usleep_range(1, 100); + gpiod_set_value_cansleep(gpio_reset, 0); + msleep_interruptible(50); + } else { + ret =3D regmap_update_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_SWRST_BIT, ADE9000_SWRST_BIT); + if (ret) + return ret; + usleep_range(80, 100); + } + + if (!st->rst_done) + return -EIO; + + return 0; +} + +static int ade9000_setup(struct ade9000_state *st) +{ + int ret; + + ret =3D regmap_multi_reg_write(st->regmap, ade9000_reg_sequence, + ARRAY_SIZE(ade9000_reg_sequence)); + if (ret) + return ret; + + msleep_interruptible(2); + + ret =3D regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); + if (ret) + return ret; + + return regmap_write(st->regmap, ADE9000_REG_STATUS1, GENMASK(31, 0)); +} + +static const struct iio_buffer_setup_ops ade9000_buffer_ops =3D { + .preenable =3D &ade9000_buffer_preenable, + .postdisable =3D &ade9000_buffer_postdisable, +}; + +static 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_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ade9000_state *st; + struct regmap *regmap; + int irq; + int ret; + + indio_dev =3D devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) { + dev_err(&spi->dev, "Unable to allocate ADE9000 IIO"); + return -ENOMEM; + } + st =3D iio_priv(indio_dev); + + st->rx =3D devm_kcalloc(&spi->dev, ADE9000_RX_DEPTH, sizeof(*st->rx), + GFP_KERNEL); + if (!st->rx) + return -ENOMEM; + + st->tx =3D devm_kcalloc(&spi->dev, ADE9000_TX_DEPTH, sizeof(*st->tx), + GFP_KERNEL); + if (!st->tx) + return -ENOMEM; + + regmap =3D devm_regmap_init(&spi->dev, NULL, spi, &ade9000_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Unable to allocate ADE9000 regmap"); + return PTR_ERR(regmap); + } + spi_set_drvdata(spi, st); + + irq =3D fwnode_irq_get_byname(dev_fwnode(&spi->dev), "irq0"); + if (irq < 0) { + dev_err(&spi->dev, "Unable to find irq0"); + return -EINVAL; + } + + ret =3D devm_request_threaded_irq(&spi->dev, irq, NULL, + ade9000_irq0_thread, + IRQF_ONESHOT, + KBUILD_MODNAME, indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to request threaded irq: %d\n", ret); + return ret; + } + + irq =3D fwnode_irq_get_byname(dev_fwnode(&spi->dev), "irq1"); + if (irq < 0) { + dev_err(&spi->dev, "Unable to find irq1"); + return -EINVAL; + } + + ret =3D devm_request_threaded_irq(&spi->dev, irq, NULL, + ade9000_irq1_thread, + IRQF_ONESHOT, + KBUILD_MODNAME, indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to request threaded irq: %d\n", ret); + return ret; + } + + st->spi =3D spi; + + indio_dev->name =3D spi_get_device_id(spi)->name; + indio_dev->dev.parent =3D &st->spi->dev; + indio_dev->info =3D &ade9000_info; + indio_dev->modes =3D INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + indio_dev->setup_ops =3D &ade9000_buffer_ops; + + st->regmap =3D regmap; + + ret =3D ade9000_setup_iio_channels(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to set up IIO channels"); + return ret; + } + ret =3D devm_iio_kfifo_buffer_setup(&spi->dev, indio_dev, + &ade9000_buffer_ops); + if (ret) + return ret; + + ret =3D ade9000_reset(st); + if (ret) { + dev_err(&spi->dev, "ADE9000 reset failed"); + return ret; + } + + ret =3D ade9000_setup(st); + if (ret) { + dev_err(&spi->dev, "Unable to setup ADE9000"); + return ret; + } + + ret =3D devm_iio_device_register(&spi->dev, indio_dev); + if (ret) { + dev_err(&spi->dev, "Unable to register IIO device"); + return ret; + } + + return ret; +}; + +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", + }, + .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.49.0