From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 6D86E384CCD; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=ahRMoRdC7GTjM/uxnPCYey1ImEsb6Y3YqGfMDj0gX6l2WS7ppgWljHV4gvotfHgTP71gUmZUuuzB9WY5aIls3ZbR4xOOjUEOSen8sx542xWgiOhn7Libb77KFUlC/lntoOa3PBNqf29cuUsRHCCtAvKqzdpkLODHacjCKa5zbZ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=eAb5oFB+rdh2Zz6njY91rxePgaWUNucu8QwqMo+DuCE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=aAFIO4O1XxBjZGcCS0uqdbEptIzmsI38OsihWCxG8YyszzzHNzIepFchB/NFpVq+dYcOL7+Vr8jc26PXrI87rv4rGW3wT11xYVK1J6faZTDnm+Ix0BYt32GNmc+UgnoBHmMbyRHY3x53ixoEyvwxYlHlDLGKP+6LBxwSbTe/FtA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Qf+AjsLh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Qf+AjsLh" Received: by smtp.kernel.org (Postfix) with ESMTPS id CF26BC2BCF5; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082994; bh=eAb5oFB+rdh2Zz6njY91rxePgaWUNucu8QwqMo+DuCE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Qf+AjsLhz4AfkZ2mvB/FOclY9mC0ye0yqp9WCofv4H6mh2NCmqOKZxU7DPfzjGw7O eVzt4CABi/TlRVW10qeMvT7cPcawn/UVA6drd6mKYmKb43r1dMa22FNLLfQTnyVtiY yAmu4sCJ9CLVlalNWeRNn17Z7BU1mpxy6x8N82IZtbZSLjF4Hdzfil3SlYL/BFCEks TWwJERX2sZ9+/lfxhHufL9a56xdXHoEAMlBtwmUTxu5mTmAlbKwxxbnMKwIlBC3B2A lduqCTpsib8q8EKbfQatzAC4LBiaAcgZSBjH3TfxJZD8R1LxD4pIyX06c7MHid8kLy U372z/RiEeRKQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF192CC6B39; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:41 -0300 Subject: [PATCH 01/10] iio: frequency: ad9910: powerdown fix 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 Message-Id: <20261015-ad9910-backend-support-v1-1-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=2033; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=z7PqLUz1GS3N66gFTTPD/4sazamj3Ede7ek83iY24FI=; b=v3kIziO3EaoK9N1dW+gWYnAJBcqYdT/6j2lGpDIPLJMxA/OeAZrnJe7PdyQBwxGHRyMoYM4AK mfY6ZmIzvwcBkwwwtsSlJZns0QgAvD2PPvv0cXt0fZCeh3DR1zIiywX X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar Enable the software powerdown on all the applicable CFR1 register bits at once with an IO update. It turns out that DIGITAL and REFCLK_INPUT powerdown do need an IO update when enabling the powerdown, but that is not the case when powering it up again. It is an asymmetric behavior, which was observed while profiling power consumption in the lab. Fixes: 22452fe6cd08 ("iio: frequency: ad9910: initial driver implementation= ") Signed-off-by: Rodrigo Alencar Reviewed-by: Nuno S=C3=A1 --- drivers/iio/frequency/ad9910.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/iio/frequency/ad9910.c b/drivers/iio/frequency/ad9910.c index 04a4e184b873..8bc24d0b7442 100644 --- a/drivers/iio/frequency/ad9910.c +++ b/drivers/iio/frequency/ad9910.c @@ -621,26 +621,16 @@ static int ad9910_sw_powerdown_set(struct ad9910_stat= e *st, bool enable) if (ad9910_sw_powerdown_get(st) =3D=3D enable) return 0; =20 - /* - * When powering down, the DAC and AUX_DAC (SW1) must be powered down - * first, as they require an I/O update to take effect. The opposite is - * true when powering up, the DAC and AUX_DAC must be powered up last, - * i.e., after the DIGITAL and REFCLK_INPUT (SW0) power up. - */ - if (enable) { - ret =3D ad9910_reg32_update(st, AD9910_REG_CFR1, - AD9910_CFR1_SW1_POWER_DOWN_MSK, - AD9910_CFR1_SW1_POWER_DOWN_MSK, - true); - if (ret) - return ret; - + if (enable) return ad9910_reg32_update(st, AD9910_REG_CFR1, - AD9910_CFR1_SW0_POWER_DOWN_MSK, - AD9910_CFR1_SW0_POWER_DOWN_MSK, - false); - } + AD9910_CFR1_SW_POWER_DOWN_MSK, + AD9910_CFR1_SW_POWER_DOWN_MSK, + true); =20 + /* + * When powering up, the DIGITAL and REFCLK_INPUT (SW0) must be powered + * up first, as they do not require an I/O update to take effect. + */ ret =3D ad9910_reg32_update(st, AD9910_REG_CFR1, AD9910_CFR1_SW0_POWER_DOWN_MSK, 0, false); if (ret) --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 70F7253D9C9; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=tq+0A29pIMaUAFAG7t5fv2JC18EydBxFQi4WW01ShS2bnFM88cKKOhdXiMVO2Xp6Ii8dQGRnt48gF2q+0q2iEXxkkttZfEoXgJU8igL3+4nA8lhfpjNylbTOdCJ0Ins7v4S1P6G+uBaQl2xtfE6BluH8KPq6NjPzRt98InH52BU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=qBeZXHM7R+eFGoiA8eSiWzdg88ngr2gc5eMV+f4Prrc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FgHW/g9d1QqEapIPCE+I9AeFGjhmCawVpDD46VTBGilw8idKM6jwcrqk/5wrR1nwMYUO4VDenNcAKtn3sP91CA62e6bnBCc6Bk+FuXX4RV+ZfcrwyJXuUucRmCBlRtXJm02VEKFHAWPu90eGGw9rT8vGxoEhIagYvgR34WVNVSc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ts3e0Cv9; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ts3e0Cv9" Received: by smtp.kernel.org (Postfix) with ESMTPS id DE98FC2BCFC; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=qBeZXHM7R+eFGoiA8eSiWzdg88ngr2gc5eMV+f4Prrc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ts3e0Cv9bjj9FVn0A/BXYpMQh6WXkUJn/HwdNAW+dbNENdSaY2Qcywr3NqmZ5EZRh n6eO3AU9JlnUtV23NlH1Qj2bihgeBqkjBYAvmeDVEa+zh0cWo4kUA53EIknGFulogJ xVuFZX+xo9FS6CSfSSqJYbIRPnB8u9YP24CdOKd1goDpN2EsdjAC/dyGfU1E6+bOAt SrmzK7j8/RECQaQLPzOim5Uh6GtjpT4AqFUl1kE2VWvGWSGgoehsj9sg6QRdeEdblC 7hDM2/DuhYHuSDbj1AgxtmCfWQiNoxiL4TxLAFKaDnA6LuCUerf5ZzUr1IQfILAZZj 0/qR+YN/XFhZA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BF7A3CCA464; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:42 -0300 Subject: [PATCH 02/10] iio: backend: add devm_iio_backend_get_optional() 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 Message-Id: <20261015-ad9910-backend-support-v1-2-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=4254; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=jMGRlIFAVCCUz4CCoYv97h4Bqb1DwkRQZ4omjdnHBPA=; b=rep/gWP6o7g0TuJDFbq5uZXAbtNeavCTcABecjt66g/dm2woALLaNAba8Ug2NM/XoRo2H/5tz jT5VQnTMh+rBpuJryTB+8YUz+Mea9VapIxuo8G5I8dpvie+TTZlLlk7 X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar Frontend devices might not need a backend driver to rely on. An IIO device that supports backends can behave differently when they are not available and that should be acceptable. Such parts may provide basic functionality solely using the control interface (SPI for instance), being able to have extended features when a backend is present. Add devm_iio_backend_get_optional(), which returns NULL when the backend is not described in firmware, i.e., when the io-backends property is not present or, for a named lookup, when the name is not listed in the io-backend-names property. Other errors, such as probe deferral, are still returned. To make that possible, a named lookup that does not match any entry of io-backend-names now fails with -ENOENT, the same error returned when the io-backends reference is missing. Also, the missing reference is no longer logged as an error, leaving that to the caller. Signed-off-by: Rodrigo Alencar Reviewed-by: Nuno S=C3=A1 --- drivers/iio/industrialio-backend.c | 34 +++++++++++++++++++++++++++++++++- include/linux/iio/backend.h | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-= backend.c index fbf5c39d7655..7af41ba50a65 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -1006,9 +1006,14 @@ static struct iio_backend *__devm_iio_backend_fwnode= _get_by_index(struct device =20 struct fwnode_handle *fwnode_back __free(fwnode_handle) =3D fwnode_find_reference(fwnode, "io-backends", index); - if (IS_ERR(fwnode_back)) + if (IS_ERR(fwnode_back)) { + /* not described in firmware, let the caller decide what to do */ + if (PTR_ERR(fwnode_back) =3D=3D -ENOENT) + return ERR_CAST(fwnode_back); + return dev_err_cast_probe(dev, fwnode_back, "Cannot get Firmware reference\n"); + } =20 guard(mutex)(&iio_back_lock); list_for_each_entry(back, &iio_back_list, entry) { @@ -1035,6 +1040,8 @@ static struct iio_backend *__devm_iio_backend_fwnode_= get(struct device *dev, con =20 if (name) { ret =3D device_property_match_string(dev, "io-backend-names", name); + if (ret =3D=3D -EINVAL || ret =3D=3D -ENODATA) + return ERR_PTR(-ENOENT); if (ret < 0) return ERR_PTR(ret); index =3D ret; @@ -1061,6 +1068,31 @@ struct iio_backend *devm_iio_backend_get(struct devi= ce *dev, const char *name) } EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, "IIO_BACKEND"); =20 +/** + * devm_iio_backend_get_optional - Optional device managed backend device = get + * @dev: Consumer device for the backend + * @name: Backend name + * + * Gets the backend associated with @dev. A backend not described in firmw= are, + * i.e., the io-backends property is not present or @name is not listed in + * the io-backend-names property, is not treated as an error. + * + * RETURNS: + * A backend pointer, NULL if the backend is not described in firmware, + * negative error pointer otherwise. + */ +struct iio_backend *devm_iio_backend_get_optional(struct device *dev, + const char *name) +{ + struct iio_backend *back =3D devm_iio_backend_get(dev, name); + + if (IS_ERR(back) && PTR_ERR(back) =3D=3D -ENOENT) + return NULL; + + return back; +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get_optional, "IIO_BACKEND"); + /** * devm_iio_backend_get_by_index - Device managed backend device get by in= dex * @dev: Consumer device for the backend diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index 9c16b695a602..93d5f2073cc3 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -267,6 +267,8 @@ int iio_backend_extend_chan_spec(struct iio_backend *ba= ck, bool iio_backend_has_caps(struct iio_backend *back, u32 caps); void *iio_backend_get_priv(const struct iio_backend *conv); struct iio_backend *devm_iio_backend_get(struct device *dev, const char *n= ame); +struct iio_backend *devm_iio_backend_get_optional(struct device *dev, + const char *name); struct iio_backend *devm_iio_backend_get_by_index(struct device *dev, unsi= gned int index); struct iio_backend *devm_iio_backend_fwnode_get(struct device *dev, const char *name, --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 75635541E65; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=OQF+4DCXXYze7PZWR96q4WJJBncJI6uxaI0R0QyfhQSUO5F8Gp7fQMA3z2FsQ/eV9AC1AP837gyXDJgp0Ly290i3N/LcoHYe7SFhUbh+CNu2spgiXDIuENKPGdNzRdsI5n42ngqXzaUnfB8G1iARnfdsf2f6iPTMgrbeJnqPEQU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=Jw7pUBGadwcJoxIiCw8ndleKgT/t2mQTcH88UX2z24A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Dm7+A/WF4Oq7WjwTKpOtnI+y3JPJ3MHK++q26rCGf4RcYNsZHg6fhOkOvi8H559pXpBEycQZGpaKg1I6P8hCxADAZ9GGhFRcMoytSi3GAU4fCn9J6OV98pvmESZnxayXirdAo0luI1iieP1sEJELS7KXPeDdIcOIiK0JDVzK4IY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RTn4uyCz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RTn4uyCz" Received: by smtp.kernel.org (Postfix) with ESMTPS id 046A3C32781; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=Jw7pUBGadwcJoxIiCw8ndleKgT/t2mQTcH88UX2z24A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=RTn4uyCzTKsE8gqyWBZB1lbcMh16WWBd4T7tTmnEPcPJtCMGyMiAWNNONwoKuzlMd Ifqv+9ZT6VzGBJFA6xqLJYYj+XZb9mHxBH6msLnWauacjtF4zePrKUG80ITyx6JpY1 PA+nIdcNcTphzPgvY/CrjLwknEE0YYEjsfUKRVU2z73R1V0n/4hCdoXRxwlOq0uxRl AtU6y1y7UunBxbc0fpAPW1Nr2Txf6amDwmfE0TntLf++sVgiREz/kiJynOeAvAa2zT kGe6aBgDt8zcpPHABLJvod1mArhuy1tyzRXy2f3sOPoaMOZNMOfMKc1DT420v2re7a xQFDn1ZdUDBeg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id CED3ECC6B38; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:43 -0300 Subject: [PATCH 03/10] dt-bindings: iio: frequency: add adi,ad9910-axi-backend 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 Message-Id: <20261015-ad9910-backend-support-v1-3-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=3655; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=3NhlsAOFJ1QmxON82V1Y+ILA5J9HSbaSpVlBemiZfX8=; b=W13EWuyVYCatrPm+Z0YoDTHgCS+/s7VyN4aHRv7FFp/9rVp2CbyDkl5Qfyd4lLfKdZsC/QU1a OSmt4rxCx8kBCDCmZqcWIkTOVjManPBMmQfOcbxujpFCzxlkFjXEjuR X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar Add bindings for the AD9910 AXI backend IP core. The FPGA IP core interfaces with the data and control pins of the AD9910 DDS, streaming data from memory via DMA into the 18-bit parallel data port (F[1:0] and D[15:0] pins), which is clocked by the PDCLK output of the device. It also drives the PROFILE[2:0] pins and the DRCTL pin, which controls the slope direction of the digital ramp generator (DRG). The DRCTL pin is driven by a PWM generator, so the IP core is described both as an IIO backend and as a PWM provider. Signed-off-by: Rodrigo Alencar --- .../iio/frequency/adi,ad9910-axi-backend.yaml | 74 ++++++++++++++++++= ++++ MAINTAINERS | 1 + 2 files changed, 75 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,ad9910-axi= -backend.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,ad9910-= axi-backend.yaml new file mode 100644 index 000000000000..20b884e8eb10 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,ad9910-axi-backen= d.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,ad9910-axi-backend.ya= ml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD9910 AXI Backend IP core + +maintainers: + - Rodrigo Alencar + +description: + FPGA IP core that interfaces with the data and control pins of the AD9910 + Direct Digital Synthesizer. The SPI bus is used as the control interface + of the AD9910 device, while this IP core streams data from memory via DMA + into the 18-bit parallel data port (F[1:0] and D[15:0] pins), which is + clocked by the PDCLK output of the AD9910. The IP core also drives the + PROFILE[2:0] pins for profile selection and provides a PWM generator that + drives the DRCTL pin, controlling the digital ramp generator (DRG) slope + direction. + + https://www.analog.com/en/products/ad9910.html + +properties: + compatible: + const: adi,ad9910-axi-backend + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: AXI bus clock (s_axi_aclk). + + dmas: + maxItems: 1 + + dma-names: + items: + - const: tx + + '#io-backend-cells': + const: 0 + + '#pwm-cells': + const: 3 + description: + The first cell must be 0, as only the DRCTL PWM output is available. + The second cell is the PWM period in nanoseconds and the third cell + holds the PWM flags. + +required: + - compatible + - reg + - clocks + - dmas + - dma-names + - '#io-backend-cells' + - '#pwm-cells' + +additionalProperties: false + +examples: + - | + ad9910_backend: dds-backend@44a00000 { + compatible =3D "adi,ad9910-axi-backend"; + reg =3D <0x44a00000 0x10000>; + clocks =3D <&clkc 15>; + dmas =3D <&tx_dma 0>; + dma-names =3D "tx"; + #io-backend-cells =3D <0>; + #pwm-cells =3D <3>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 3a2dfd1a4fd8..93ad6a829cb3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1731,6 +1731,7 @@ S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/ABI/testing/debugfs-iio-ad9910 F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9910 +F: Documentation/devicetree/bindings/iio/frequency/adi,ad9910-axi-backend.= yaml F: Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml F: Documentation/iio/ad9910.rst F: drivers/iio/frequency/ad9910.c --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 710A354145D; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=blVqkyuNhIo3AJ5cH7m4vbkLyfHi6cu2AP944136pYVKQZhfYLLIBMGpzW1BiXMce0DAHz6NItupT0uSAx36Wx6xq2PCba/3zQKJ/0dJA9R+stVG7alRxMCk/0c5HObTwJ0PNKgwMqbGZnxysjxlJPRrskTNhX12Op+jW9KCKBQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=AaImLE0FEDxw87MGpv3hMNABB731sE/Jzx2WPzMFp5c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ieFjw/Uxzorwa4dN6wLnA9oYmd6BNB+bIk0uOa63NaS7TQsKrds3wLcrXmhKC5KgSMjKgdAVay6RtS8tFfCeOZOV2+3dJtbxnHLahgQtd69YJZj76kf73Q1+DyHw8vtzf0fPYdP/DEOXcBhSM8C2rtN/FMNZ9vR5/1k9xW566Iw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NMKHz9S1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NMKHz9S1" Received: by smtp.kernel.org (Postfix) with ESMTPS id F0915C2BD01; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=AaImLE0FEDxw87MGpv3hMNABB731sE/Jzx2WPzMFp5c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=NMKHz9S1EqrJA/oyzomBZAjprJP98YI1R1V01OCRYTvLieX8OxcR1r/9PU9RoufKk /JWugdmXAGzMpFCPrjAOlmaAjlRiJUXdvGnZ03L4GESQJ0Z8vl3goaOW53UVR8i3or A0UHUEn+2IwWLAqCaavEZr1MLb+sn/oxTXh5XxcG3UDZ/XOQLTgYffUL99mijULAac 6rJYlMPOPhqM0Dm6KaqAfTxiJYQO6iPsd3jAAeq6lftsCIwlU/sKMAEsIGM2gFT8XL 7DgLTmu/YZCNB5epTp0a2Tv3nPScmDF+naCn3OyXPHMppFoZUNNZ2fTanWKFq8XFfF QanYarmbNJmpQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE13CCCA466; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:44 -0300 Subject: [PATCH 04/10] dt-bindings: iio: frequency: ad9910: add io-backends property 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 Message-Id: <20261015-ad9910-backend-support-v1-4-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=2527; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=8jAo3Ub+lq360SLcTWJHf+ffhTCESzkP7WQXUZzi1Yw=; b=5bAk63xs1Vpwrtx+6vqlMosUp8ugrwZu08aBnPmW6Z1DUFERxhVFTj0mIdo8rn5z86y3G+dSy wUJlVgncKG/DcXTXxfDbMk2ztxvOZbq4YQkVtk0xqMvrkZNKZxdgles X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar The AD9910 parallel data port allows high-speed modulation of the DDS core parameters, which requires a data source such as an FPGA IP core connected to the F[1:0] and D[15:0] pins. Add the io-backends property, so that an IIO backend providing such interface can be referenced. The property is optional as the parallel port is. The device remains functional through the SPI control interface only, as other modes can be used to drive the DDS core. Signed-off-by: Rodrigo Alencar Acked-by: Conor Dooley --- .../bindings/iio/frequency/adi,ad9910.yaml | 38 ++++++++++++++++++= ++++ 1 file changed, 38 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yam= l b/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml index 4eebbd388b27..02fd49db93ff 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml @@ -120,6 +120,13 @@ properties: items: - const: drctl =20 + io-backends: + maxItems: 1 + description: + IIO backend that interfaces with the parallel data port, enabling da= ta + streaming into the device. The backend may also drive the PROFILE[2:= 0] + and DRCTL pins, the latter being exposed as a PWM provider. + adi,pll-enable: type: boolean description: @@ -206,4 +213,35 @@ examples: adi,refclk-out-drive-strength =3D "disabled"; }; }; + - | + #include + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + dds@0 { + compatible =3D "adi,ad9910"; + reg =3D <0>; + spi-max-frequency =3D <1000000>; + + #clock-cells =3D <1>; + clock-output-names =3D "sync_clk", "pdclk", "sync_out"; + + clocks =3D <&ad9910_refclk>; + clock-names =3D "ref_clk"; + + dvdd-io33-supply =3D <&vdd_io33>; + avdd33-supply =3D <&vdd_a33>; + dvdd18-supply =3D <&vdd_d18>; + avdd18-supply =3D <&vdd_a18>; + + reset-gpios =3D <&gpio 0 GPIO_ACTIVE_HIGH>; + io-reset-gpios =3D <&gpio 1 GPIO_ACTIVE_HIGH>; + powerdown-gpios =3D <&gpio 2 GPIO_ACTIVE_HIGH>; + update-gpios =3D <&gpio 3 GPIO_ACTIVE_HIGH>; + + io-backends =3D <&ad9910_backend>; + pwms =3D <&ad9910_backend 0 1000000 0>; + pwm-names =3D "drctl"; + }; + }; ... --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 86A855437FB; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=kINoSYu6a2omyOvk4NdUqkgPcd0n3oKIKqG8zdukzMsG1Ujdo0Xh28Ov69SW0pPztJdNunHMhYesxInGYCI3ftIHTdKcG9/G8LCkzPt6CjxZ4VAWDNmTX2OMMlbywSb1wdlSRK+wGGNTItrV4gp4AmXj7mKclp8zUIkQjn0DKGQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=JNXa9EY9DorVXCpgEHNR1iSm211urEUD88TNEug/caA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kKWGiJlRsDQ3xo45ueJ7Z/dubQWFC79b386Cf5Fv8DdNLteqo/egFmaJxgqKHHVH9BFVugGg7+KYEDBIojjVG4hzboate2ZIRnHFhfEeZKORqd6cXX85jkwHO/TvNi4bDi8u5oZoIe1XF/UEV4HNIIvNlGHqFc7J1IcDszM4+zQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PMoczZ7i; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PMoczZ7i" Received: by smtp.kernel.org (Postfix) with ESMTPS id 0DF89C4AF0B; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=JNXa9EY9DorVXCpgEHNR1iSm211urEUD88TNEug/caA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=PMoczZ7ii2uTxjAj0lwjb/XFXJ1yFERFSMZ/iq467DgIwiKkJpI9oX5XHEx6HruSO f0ZyUaQoaZeJfGpEKZjY/7lSweppKbESDgVYdllwEpe0SzbWFBGWMZwFvYf71jQhDN N4WW0enWrFLIhGWHXyS3SVcDNxP18NkQto7bDYNJjz4bclK1sPWeRD5hREnJnUME2j tlMgJLoyKiCqKlNmjSvHhGRIeyvt/7VCHy4FJvQZgqgcsNgLLVZ/EqgDu8E7+NgVEL oZwpALhsBWjesms/NNT+/TDIuRAv2WWf+VyIQ73bcuvnqDbTxZiR6ofS3hmWtPWhtP Dte0tOFbliolQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EDC84CC6B39; Thu, 15 Oct 2026 16:49:54 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:45 -0300 Subject: [PATCH 05/10] iio: frequency: ad9910: move channel indexes into a shared header 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 Message-Id: <20261015-ad9910-backend-support-v1-5-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=4329; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=VsqJQc+ePynwFhVyVl6Uf/Qo3uusPG2hDGbHDjQCWp0=; b=/CtkwCFECJiXQy82RHizUoY1L5pL8v0dEkVDf9WFdxSwKGcRXjmJODpFTeuOxLWX176uDGKmM foVnVG0qwpzDe9lXDZj+Mnprl0WimFHjcChHUyMHzF9pnD1uTLBCupR X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar The channel indexes are used as channel identifiers in IIO backend operations, such as enabling a parallel data port destination or selecting a profile. Move them, along with the data destination definitions, into a shared header, so that the frontend and backend drivers agree on those identifiers. No functional change. Signed-off-by: Rodrigo Alencar Reviewed-by: Nuno S=C3=A1 --- MAINTAINERS | 1 + drivers/iio/frequency/ad9910.c | 35 ++------------------------------- drivers/iio/frequency/ad9910.h | 44 ++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 93ad6a829cb3..a9cb4396b3e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1735,6 +1735,7 @@ F: Documentation/devicetree/bindings/iio/frequency/ad= i,ad9910-axi-backend.yaml F: Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml F: Documentation/iio/ad9910.rst F: drivers/iio/frequency/ad9910.c +F: drivers/iio/frequency/ad9910.h =20 ANALOG DEVICES INC MAX22007 DRIVER M: Janani Sunil diff --git a/drivers/iio/frequency/ad9910.c b/drivers/iio/frequency/ad9910.c index 8bc24d0b7442..dc13986dff3d 100644 --- a/drivers/iio/frequency/ad9910.c +++ b/drivers/iio/frequency/ad9910.c @@ -33,6 +33,8 @@ #include #include =20 +#include "ad9910.h" + /* Register addresses */ #define AD9910_REG_CFR1 0x00 #define AD9910_REG_CFR2 0x01 @@ -194,11 +196,6 @@ #define AD9910_RAM_ENABLED(st) \ FIELD_GET(AD9910_CFR1_RAM_ENABLE_MSK, (st)->reg[AD9910_REG_CFR1].val32) =20 -#define AD9910_DEST_FREQUENCY 0 -#define AD9910_DEST_PHASE 1 -#define AD9910_DEST_AMPLITUDE 2 -#define AD9910_DEST_POLAR 3 - /* PLL constants */ #define AD9910_PLL_MIN_N 12 #define AD9910_PLL_MAX_N 127 @@ -302,34 +299,6 @@ struct ad9910_ram_fw { __be32 words[] __counted_by_be(wcount); } __packed; =20 -enum { - AD9910_CHAN_IDX_PHY, - AD9910_CHAN_IDX_PROFILE_0, - AD9910_CHAN_IDX_PROFILE_1, - AD9910_CHAN_IDX_PROFILE_2, - AD9910_CHAN_IDX_PROFILE_3, - AD9910_CHAN_IDX_PROFILE_4, - AD9910_CHAN_IDX_PROFILE_5, - AD9910_CHAN_IDX_PROFILE_6, - AD9910_CHAN_IDX_PROFILE_7, - AD9910_CHAN_IDX_PARALLEL_AMP, - AD9910_CHAN_IDX_PARALLEL_PHASE, - AD9910_CHAN_IDX_PARALLEL_FREQ, - AD9910_CHAN_IDX_PARALLEL_POLAR_AMP, - AD9910_CHAN_IDX_PARALLEL_POLAR_PHASE, - AD9910_CHAN_IDX_DRG_FREQ, - AD9910_CHAN_IDX_DRG_PHASE, - AD9910_CHAN_IDX_DRG_AMP, - AD9910_CHAN_IDX_DRG_FREQ_RAMP_UP, - AD9910_CHAN_IDX_DRG_FREQ_RAMP_DOWN, - AD9910_CHAN_IDX_DRG_PHASE_RAMP_UP, - AD9910_CHAN_IDX_DRG_PHASE_RAMP_DOWN, - AD9910_CHAN_IDX_DRG_AMP_RAMP_UP, - AD9910_CHAN_IDX_DRG_AMP_RAMP_DOWN, - AD9910_CHAN_IDX_RAM, - AD9910_CHAN_IDX_OSK, -}; - enum { AD9910_POWERDOWN, AD9910_DWELL_EN, diff --git a/drivers/iio/frequency/ad9910.h b/drivers/iio/frequency/ad9910.h new file mode 100644 index 000000000000..6452a8678ed9 --- /dev/null +++ b/drivers/iio/frequency/ad9910.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * AD9910 SPI DDS (Direct Digital Synthesizer) driver + * + * Copyright 2026 Analog Devices Inc. + */ + +#ifndef IIO_FREQUENCY_AD9910_H_ +#define IIO_FREQUENCY_AD9910_H_ + +#define AD9910_DEST_FREQUENCY 0 +#define AD9910_DEST_PHASE 1 +#define AD9910_DEST_AMPLITUDE 2 +#define AD9910_DEST_POLAR 3 + +enum ad9910_channel_idx { + AD9910_CHAN_IDX_PHY, + AD9910_CHAN_IDX_PROFILE_0, + AD9910_CHAN_IDX_PROFILE_1, + AD9910_CHAN_IDX_PROFILE_2, + AD9910_CHAN_IDX_PROFILE_3, + AD9910_CHAN_IDX_PROFILE_4, + AD9910_CHAN_IDX_PROFILE_5, + AD9910_CHAN_IDX_PROFILE_6, + AD9910_CHAN_IDX_PROFILE_7, + AD9910_CHAN_IDX_PARALLEL_AMP, + AD9910_CHAN_IDX_PARALLEL_PHASE, + AD9910_CHAN_IDX_PARALLEL_FREQ, + AD9910_CHAN_IDX_PARALLEL_POLAR_AMP, + AD9910_CHAN_IDX_PARALLEL_POLAR_PHASE, + AD9910_CHAN_IDX_DRG_FREQ, + AD9910_CHAN_IDX_DRG_PHASE, + AD9910_CHAN_IDX_DRG_AMP, + AD9910_CHAN_IDX_DRG_FREQ_RAMP_UP, + AD9910_CHAN_IDX_DRG_FREQ_RAMP_DOWN, + AD9910_CHAN_IDX_DRG_PHASE_RAMP_UP, + AD9910_CHAN_IDX_DRG_PHASE_RAMP_DOWN, + AD9910_CHAN_IDX_DRG_AMP_RAMP_UP, + AD9910_CHAN_IDX_DRG_AMP_RAMP_DOWN, + AD9910_CHAN_IDX_RAM, + AD9910_CHAN_IDX_OSK, +}; + +#endif /* IIO_FREQUENCY_AD9910_H_ */ --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 79B4A542EEE; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=qEHMLerQU2Pb90/or/ACtqSMTmeAt6N6/L+3SYmEyXYNy1EkHTJXvkpeaOKTrZEGZgYABAu3mhPzxlYGmhiJZEh9X/iank78etnkvGrmivIoeyk80eMMHCWxPIkF0GwAyauX4xzVUj+PmyaoCIUH9wtUq9u7E2rKeKCZFOS3jQg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=twxHn1Sa2xtmpgYIMApvVRr7bkrFmQmOYjsco0YLF+Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=e1mHc5OZfdJECHLrFaaL0gsxM9c8W4M4oBZcJa/esRGU+cdpm/vQ7Unq/fopHwqLuEhZ0KooajKMKlRMuz28C9zaV978nm4O4svZF/0K0KfkI4h+r1nzVJRD4Yg1HrJKnA4k+ml3CErgHobHt9m6QeDvCWhQrYWmlLJIyM+eGGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dVVKYwRS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dVVKYwRS" Received: by smtp.kernel.org (Postfix) with ESMTPS id 1F2E3C4AF17; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=twxHn1Sa2xtmpgYIMApvVRr7bkrFmQmOYjsco0YLF+Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=dVVKYwRSqXDRqcoqyNt5gsIroaPvqFgtoL0jtauOHjE9ghnYOPtM4iotTwrwgHcld mtYBPycU7BQG6mbVVpTAHj0o3w3EgpbznRQN8x3vQkbk4UYCPeudG2T7Fh/uZ0xTv8 1/1tqGUitPMNvHiBx+Wb5nMApvrTNsaa5kP4JMM/lo5COR0U4vdUjiSE4Fa+W1/J3g tUaZnggeDVto82UNYZl8a9V7TWtBUJ6azzBdkBew10dluKBLSjlpDy+SctxDojPPxh kY3gKWbZsecXp1nmZaRxzOcJyeoND0lFyma8nLuK0DEb3UhuvRXjZHH159+WswfQzn UTZaNMo4wftyw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A51FCC6B33; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:46 -0300 Subject: [PATCH 06/10] iio: frequency: ad9910: add axi backend driver 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 Message-Id: <20261015-ad9910-backend-support-v1-6-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=14888; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=XfuzLOIG3CdJGmC6H/5fgpP60BtJ7Wf2VfwhRUiUfLs=; b=fIG+RWV5bxDXN3EUqyZ1FH8LFA02it77jhtrWxp+l8zV6Ok6EPsyq/rIfrcXyd9mH+8nLqRdp /mycUUAqNEYAQWICiA9ylhUmYbZcBicA6Kvsf52l4fIzBBxst4puZwE X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar Add the driver for the AD9910 AXI backend IP core, which interfaces with the data and control pins of the AD9910 DDS. It registers as an IIO backend that provides: - a DMA output buffer that streams data into the parallel data port; - the parallel data destination (F[1:0] pins) and data rate, derived from the PDCLK frequency; - the PROFILE[2:0] pins control, through profile channel enables. It also registers a PWM chip with a single output driving the DRCTL pin, which the AD9910 driver uses to control the digital ramp generator direction. PWM period and duty cycle are programmed in PDCLK cycles. Signed-off-by: Rodrigo Alencar --- MAINTAINERS | 1 + drivers/iio/frequency/Kconfig | 17 ++ drivers/iio/frequency/Makefile | 1 + drivers/iio/frequency/ad9910-axi-backend.c | 396 +++++++++++++++++++++++++= ++++ 4 files changed, 415 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a9cb4396b3e1..c3cda855dabb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1734,6 +1734,7 @@ F: Documentation/ABI/testing/sysfs-bus-iio-frequency-= ad9910 F: Documentation/devicetree/bindings/iio/frequency/adi,ad9910-axi-backend.= yaml F: Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml F: Documentation/iio/ad9910.rst +F: drivers/iio/frequency/ad9910-axi-backend.c F: drivers/iio/frequency/ad9910.c F: drivers/iio/frequency/ad9910.h =20 diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 994d199080eb..f7f5c3cce005 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -42,6 +42,23 @@ config AD9910 To compile this driver as a module, choose M here: the module will be called ad9910. =20 +config AD9910_AXI_BACKEND + tristate "Analog Devices AD9910 AXI Backend driver" + depends on AD9910 + depends on HAS_IOMEM && PWM + select IIO_BACKEND + select IIO_BUFFER + select IIO_BUFFER_DMAENGINE + select REGMAP_MMIO + help + Say yes here to build support for the AXI Backend Driver for the + Analog Devices AD9910 DDS. The IP core is used to drive digital ramp + control pins and interface with the parallel data port of the AD9910 + device. + + To compile this driver as a module, choose M here: the + module will be called ad9910-axi-backend. + endmenu =20 # diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index e3b1d36ed620..bfac9e205e81 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD9523) +=3D ad9523.o obj-$(CONFIG_AD9910) +=3D ad9910.o +obj-$(CONFIG_AD9910_AXI_BACKEND) +=3D ad9910-axi-backend.o obj-$(CONFIG_ADF41513) +=3D adf41513.o obj-$(CONFIG_ADF4350) +=3D adf4350.o obj-$(CONFIG_ADF4371) +=3D adf4371.o diff --git a/drivers/iio/frequency/ad9910-axi-backend.c b/drivers/iio/frequ= ency/ad9910-axi-backend.c new file mode 100644 index 000000000000..f94cb54af517 --- /dev/null +++ b/drivers/iio/frequency/ad9910-axi-backend.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AD9910 AXI Backend driver + * + * Copyright 2026 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ad9910.h" + +/* Register addresses */ +#define AD9910_AXI_REG_RESET 0x040 +#define AD9910_AXI_REG_DRG 0x084 +#define AD9910_AXI_REG_PROFILE 0x088 +#define AD9910_AXI_REG_DRCTL_PERIOD 0x08C +#define AD9910_AXI_REG_DRCTL_WIDTH 0x090 +#define AD9910_AXI_REG_RAMP_DELAY_BST 0x094 +#define AD9910_AXI_REG_BURST_COUNT 0x098 +#define AD9910_AXI_REG_BURST_DELAY 0x09C +#define AD9910_AXI_REG_RAMP_CFG 0x0A0 + +#define AD9910_AXI_REG_UPDATE_CTRL 0x104 +#define AD9910_AXI_REG_PAR_RATE 0x108 +#define AD9910_AXI_REG_F_CFG 0x10C + +#define AD9910_AXI_REG_RESET_CORE_MSK BIT(0) + +#define AD9910_AXI_REG_DRG_DRCTL_MSK BIT(2) +#define AD9910_AXI_REG_DRG_TOGGLE_EN_MSK BIT(3) + +#define AD9910_AXI_REG_RAMP_CFG_ONE_SHOT_MSK GENMASK(1, 0) +#define AD9910_AXI_REG_BURST_COUNT_MSK GENMASK(19, 0) + +#define AD9910_AXI_REG_UPDATE_RATE_MSK BIT(0) +#define AD9910_AXI_REG_UPDATE_PAR_IF_EN_MSK BIT(1) +#define AD9910_AXI_REG_UPDATE_EXT_TRIG_MSK BIT(2) + +#define AD9910_AXI_REG_PROFILE_MSK GENMASK(2, 0) +#define AD9910_AXI_REG_IO_UPDATE_MSK BIT(0) +#define AD9910_AXI_REG_F_CFG_MSK GENMASK(1, 0) + +#define AD9910_AXI_PD_CLK_MAX_FREQ_HZ (250ULL * HZ_PER_MHZ) +#define AD9910_AXI_PAR_RATE_MAX U16_MAX +#define AD9910_AXI_ONE_SHOT_BURST 1 + +struct ad9910_axi_state { + struct device *dev; + struct regmap *regmap; + /* + * lock to protect multiple accesses to the device registers and global + * data/variables. + */ + struct mutex lock; + u64 pd_clk_freq_uhz; + enum pwm_polarity pwm_polarity; +}; + +static int ad9910_axi_chan_enable(struct iio_backend *back, unsigned int c= han) +{ + struct ad9910_axi_state *st =3D iio_backend_get_priv(back); + int ret; + + guard(mutex)(&st->lock); + + switch (chan) { + /* + * Profiles are mutually exclusive, as the PROFILE[2:0] pins always + * select one of them. Enabling a profile channel selects it, which + * implicitly disables the previously selected one, hence there is + * nothing to do when disabling a profile channel. + */ + case AD9910_CHAN_IDX_PROFILE_0 ... AD9910_CHAN_IDX_PROFILE_7: + chan -=3D AD9910_CHAN_IDX_PROFILE_0; + return regmap_update_bits(st->regmap, AD9910_AXI_REG_PROFILE, + AD9910_AXI_REG_PROFILE_MSK, + FIELD_PREP(AD9910_AXI_REG_PROFILE_MSK, chan)); + case AD9910_CHAN_IDX_PARALLEL_AMP ... AD9910_CHAN_IDX_PARALLEL_POLAR_PHAS= E: + chan =3D min(chan - AD9910_CHAN_IDX_PARALLEL_AMP, AD9910_DEST_POLAR); + ret =3D regmap_update_bits(st->regmap, AD9910_AXI_REG_F_CFG, + AD9910_AXI_REG_F_CFG_MSK, chan); + if (ret) + return ret; + + return regmap_set_bits(st->regmap, AD9910_AXI_REG_UPDATE_CTRL, + AD9910_AXI_REG_UPDATE_PAR_IF_EN_MSK); + default: + return -EINVAL; + } +} + +static int ad9910_axi_chan_disable(struct iio_backend *back, unsigned int = chan) +{ + struct ad9910_axi_state *st =3D iio_backend_get_priv(back); + + switch (chan) { + case AD9910_CHAN_IDX_PARALLEL_AMP ... AD9910_CHAN_IDX_PARALLEL_POLAR_PHAS= E: + return regmap_clear_bits(st->regmap, AD9910_AXI_REG_UPDATE_CTRL, + AD9910_AXI_REG_UPDATE_PAR_IF_EN_MSK); + default: + return -EINVAL; + } +} + +static struct iio_buffer *ad9910_axi_request_buffer(struct iio_backend *ba= ck, + struct iio_dev *indio_dev) +{ + struct ad9910_axi_state *st =3D iio_backend_get_priv(back); + const char *dma_name; + + if (device_property_read_string(st->dev, "dma-names", &dma_name)) + dma_name =3D "tx"; + + return iio_dmaengine_buffer_setup_ext(st->dev, indio_dev, dma_name, + IIO_BUFFER_DIRECTION_OUT); +} + +static void ad9910_axi_free_buffer(struct iio_backend *back, + struct iio_buffer *buffer) +{ + iio_dmaengine_buffer_teardown(buffer); +} + +static int ad9910_axi_set_sample_rate(struct iio_backend *back, + unsigned int chan, u64 sample_rate) +{ + struct ad9910_axi_state *st =3D iio_backend_get_priv(back); + u64 div; + int ret; + + guard(mutex)(&st->lock); + + switch (chan) { + case AD9910_CHAN_IDX_PHY: + if (!sample_rate || sample_rate > 4 * AD9910_AXI_PD_CLK_MAX_FREQ_HZ) + return -EINVAL; + + st->pd_clk_freq_uhz =3D sample_rate * MICROHZ_PER_HZ >> 2; + return 0; + case AD9910_CHAN_IDX_PARALLEL_AMP ... AD9910_CHAN_IDX_PARALLEL_POLAR_PHAS= E: + if (!sample_rate || sample_rate > AD9910_AXI_PD_CLK_MAX_FREQ_HZ) + return -EINVAL; + + sample_rate *=3D MICROHZ_PER_HZ; + div =3D DIV64_U64_ROUND_CLOSEST(st->pd_clk_freq_uhz, sample_rate); + div =3D clamp(div, 1U, AD9910_AXI_PAR_RATE_MAX); + ret =3D regmap_write(st->regmap, AD9910_AXI_REG_PAR_RATE, div - 1); + if (ret) + return ret; + + return regmap_set_bits(st->regmap, AD9910_AXI_REG_UPDATE_CTRL, + AD9910_AXI_REG_UPDATE_RATE_MSK); + default: + return -EINVAL; + } +} + +static int ad9910_axi_read_raw(struct iio_backend *back, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ad9910_axi_state *st =3D iio_backend_get_priv(back); + u32 div; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->address) { + case AD9910_CHAN_IDX_PARALLEL_AMP ... AD9910_CHAN_IDX_PARALLEL_POLAR_PHA= SE: { + guard(mutex)(&st->lock); + + ret =3D regmap_read(st->regmap, AD9910_AXI_REG_PAR_RATE, + &div); + if (ret) + return ret; + + iio_val_s64_decompose(div_s64(st->pd_clk_freq_uhz, div + 1), + val, val2); + return IIO_VAL_DECIMAL64_MICRO; + } + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad9910_axi_reg_access(struct iio_backend *back, unsigned int re= g, + unsigned int writeval, unsigned int *readval) +{ + struct ad9910_axi_state *st =3D iio_backend_get_priv(back); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static const struct iio_backend_ops ad9910_axi_iio_back_ops =3D { + .chan_enable =3D ad9910_axi_chan_enable, + .chan_disable =3D ad9910_axi_chan_disable, + .request_buffer =3D ad9910_axi_request_buffer, + .free_buffer =3D ad9910_axi_free_buffer, + .set_sample_rate =3D ad9910_axi_set_sample_rate, + .read_raw =3D ad9910_axi_read_raw, + .debugfs_reg_access =3D iio_backend_debugfs_ptr(ad9910_axi_reg_access), +}; + +static const struct iio_backend_info ad9910_axi_back_info =3D { + .name =3D "ad9910-axi", + .ops =3D &ad9910_axi_iio_back_ops, +}; + +static const struct regmap_config ad9910_axi_regmap_config =3D { + .val_bits =3D 32, + .reg_bits =3D 32, + .reg_stride =3D 4, + .max_register =3D 0x0800, +}; + +static int ad9910_axi_pwm_apply(struct pwm_chip *chip, struct pwm_device *= pwm, + const struct pwm_state *state) +{ + struct ad9910_axi_state *st =3D pwmchip_get_drvdata(chip); + u64 period, duty; + int ret; + + guard(mutex)(&st->lock); + + period =3D mul_u64_u64_div_u64(state->period, st->pd_clk_freq_uhz, + 1ULL * NANO * MICROHZ_PER_HZ); + period =3D min(period, U32_MAX); + duty =3D mul_u64_u64_div_u64(state->duty_cycle, st->pd_clk_freq_uhz, + 1ULL * NANO * MICROHZ_PER_HZ); + duty =3D min(duty, period); + + if (state->polarity =3D=3D PWM_POLARITY_INVERSED) + duty =3D period - duty; + + ret =3D regmap_write(st->regmap, AD9910_AXI_REG_DRCTL_PERIOD, period); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, AD9910_AXI_REG_DRCTL_WIDTH, duty); + if (ret) + return ret; + + st->pwm_polarity =3D state->polarity; + + if (state->enabled) + return regmap_set_bits(st->regmap, AD9910_AXI_REG_DRG, + AD9910_AXI_REG_DRG_TOGGLE_EN_MSK); + + return regmap_clear_bits(st->regmap, AD9910_AXI_REG_DRG, + AD9910_AXI_REG_DRG_TOGGLE_EN_MSK); +} + +static int ad9910_axi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct ad9910_axi_state *st =3D pwmchip_get_drvdata(chip); + u32 period, width, drg; + int ret; + + guard(mutex)(&st->lock); + + ret =3D regmap_read(st->regmap, AD9910_AXI_REG_DRCTL_PERIOD, &period); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, AD9910_AXI_REG_DRCTL_WIDTH, &width); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, AD9910_AXI_REG_DRG, &drg); + if (ret) + return ret; + + state->period =3D mul_u64_u64_div_u64_roundup((u64)period * NANO, + MICROHZ_PER_HZ, + st->pd_clk_freq_uhz); + if (st->pwm_polarity =3D=3D PWM_POLARITY_INVERSED) + width =3D period - width; + state->duty_cycle =3D mul_u64_u64_div_u64_roundup((u64)width * NANO, + MICROHZ_PER_HZ, + st->pd_clk_freq_uhz); + state->polarity =3D st->pwm_polarity; + state->enabled =3D FIELD_GET(AD9910_AXI_REG_DRG_TOGGLE_EN_MSK, drg); + + return 0; +} + +static const struct pwm_ops ad9910_axi_pwm_ops =3D { + .apply =3D ad9910_axi_pwm_apply, + .get_state =3D ad9910_axi_pwm_get_state, +}; + +static int ad9910_axi_setup(struct ad9910_axi_state *st) +{ + int ret; + + st->pd_clk_freq_uhz =3D AD9910_AXI_PD_CLK_MAX_FREQ_HZ * MICROHZ_PER_HZ; + + ret =3D regmap_set_bits(st->regmap, AD9910_AXI_REG_RESET, + AD9910_AXI_REG_RESET_CORE_MSK); + if (ret) + return ret; + + return regmap_clear_bits(st->regmap, AD9910_AXI_REG_RESET, + AD9910_AXI_REG_RESET_CORE_MSK); +} + +static int ad9910_axi_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct ad9910_axi_state *st; + struct pwm_chip *pwm; + void __iomem *base; + struct clk *clk; + int ret; + + pwm =3D devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*st)); + if (IS_ERR(pwm)) + return PTR_ERR(pwm); + + st =3D pwmchip_get_drvdata(pwm); + + base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); + + st->dev =3D dev; + st->regmap =3D devm_regmap_init_mmio(dev, base, + &ad9910_axi_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "failed to init register map\n"); + + ret =3D devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + ret =3D ad9910_axi_setup(st); + if (ret) + return dev_err_probe(dev, ret, "failed to setup device\n"); + + pwm->ops =3D &ad9910_axi_pwm_ops; + + ret =3D devm_pwmchip_add(dev, pwm); + if (ret) + return dev_err_probe(dev, ret, "Could not register PWM chip\n"); + + return devm_iio_backend_register(dev, &ad9910_axi_back_info, st); +} + +static const struct of_device_id ad9910_axi_of_match[] =3D { + { .compatible =3D "adi,ad9910-axi-backend" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad9910_axi_of_match); + +static struct platform_driver ad9910_axi_driver =3D { + .driver =3D { + .name =3D "ad9910-axi-backend", + .of_match_table =3D ad9910_axi_of_match, + }, + .probe =3D ad9910_axi_probe, +}; +module_platform_driver(ad9910_axi_driver); + +MODULE_AUTHOR("Rodrigo Alencar "); +MODULE_DESCRIPTION("Analog Devices AD9910 AXI Backend driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("IIO_BACKEND"); --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 9FA7B41A4FD; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=dNsKxT8JQJGstKPb+y0miUSbsSe3k77ljtlCPvpG+5ahXoTrL8M2G78TqCgmNOtKQ1GLb1FOG295ulXZSj6fWeBOqsnnpxoMjz1KGFKoBwX5M78ZPkkMmROqT+uIxpPMrCbS/0oYLdWYJGHW8bPOx0aR2mSof4WckJSFjWZ8KVY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=sJ6Z8/WVLZIBxbXyU3gmvYRv6vrjKI7MPOAiduU81GE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Pg+rv83UaaQ9yAyjVmT5WFsDwfHVEwEKbmW4S8VOvTUfNRVlNi/TWYf5FYH06WqS+uJrRwGKhayPbq3Y6TbqDuAHUV1w0TLYnFtksFtWlQ5DViE5H39+Day3HXfcYATMCk6cKFCm2vkeLOm3eHCbTO7mHYfFl5A3vTNP4muQ50Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tH9itzjN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tH9itzjN" Received: by smtp.kernel.org (Postfix) with ESMTPS id 324C5C2BD05; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=sJ6Z8/WVLZIBxbXyU3gmvYRv6vrjKI7MPOAiduU81GE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=tH9itzjNt+nVToHHM8C4744JGhas40cHNDiphKzCJnDAN0GNrXtIvnj2Fmg4MdGMb uAcO0pCwU7t4jvIRU/oChB0ij/zO9WDT1z0NiLw8Ckr3RLhV7z8hf2zP9WemX7BG+n k27uUi5ogfhwBSr8Hi+L8PxV9U7HtM/VypOLMtdsN0OIpp21zq4gHFTXqCuf6uIHHP g5LuXbTZrgikWfNnWHM9SYsFNqZLXutJ5eqzHNXh77TPlh7R8n7sagHM5kZTIXLnVF 4RGs3gwuUbavJ+dMOKI9BKvr5QNVgfkDezAQWhyBM9XIuDz2EZHgw2LuTCHDKfpNcm FJ/1ULEovPDuA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1A6DECCA465; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:47 -0300 Subject: [PATCH 07/10] iio: frequency: ad9910: support drctl control 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 Message-Id: <20261015-ad9910-backend-support-v1-7-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=8743; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=KYKjnOTjR5bKxvX4oXf3lCiVSWZ0EG1nyxGjh/mX3Ts=; b=9b/6zETxuHc24MxegXObioS0fm3Kqpn0EtUkcpo3qSCVtvV3A9Rqr3UmmV0SaJRf4X/M4dAe4 txE16f84y5wD9tXGrjkUCIsT7UbjdG6pWyDMgrAl8MXIqqB7eSRoQkY X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar The DRCTL pin controls the slope direction of the AD9910 digital ramp generator (DRG). When dwell is enabled at a ramp limit, the DRG holds that limit until the next DRCTL transition, so the sweep pattern is defined by the waveform applied to that pin, which can be generated by a PWM. Get the optional "drctl" PWM and expose the integration_time attribute in the DRG ramp up and ramp down channels, which sets the time interval assigned to each ramp direction while the sweep parameter is accumulating. The PWM is disabled when the resulting period is zero. The applied state is read back, so that integration_time reports the intervals achieved by the PWM provider. Writing to integration_time fails with -EOPNOTSUPP when no DRCTL PWM is available. Signed-off-by: Rodrigo Alencar --- drivers/iio/frequency/ad9910.c | 132 +++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 126 insertions(+), 6 deletions(-) diff --git a/drivers/iio/frequency/ad9910.c b/drivers/iio/frequency/ad9910.c index dc13986dff3d..3d517879dee3 100644 --- a/drivers/iio/frequency/ad9910.c +++ b/drivers/iio/frequency/ad9910.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -324,12 +325,16 @@ union ad9910_reg { struct ad9910_state { struct spi_device *spi; struct clk *refclk; + struct pwm_device *drctl_pwm; struct fw_upload *ram_fwu; =20 struct gpio_desc *gpio_pwdown; struct gpio_desc *gpio_update; struct gpio_descs *gpio_profile; =20 + s64 ramp_up_time_ns; + s64 ramp_down_time_ns; + /* cached registers */ union ad9910_reg reg[AD9910_REG_NUM_CACHED]; =20 @@ -609,6 +614,66 @@ static int ad9910_sw_powerdown_set(struct ad9910_state= *st, bool enable) AD9910_CFR1_SW1_POWER_DOWN_MSK, 0, true); } =20 +static int ad9910_drctl_sync(struct ad9910_state *st) +{ + struct pwm_state state; + bool ndh, ndl; + int ret; + + if (!st->drctl_pwm) + return 0; + + ndh =3D FIELD_GET(AD9910_CFR2_DRG_NO_DWELL_HIGH_MSK, + st->reg[AD9910_REG_CFR2].val32); + ndl =3D FIELD_GET(AD9910_CFR2_DRG_NO_DWELL_LOW_MSK, + st->reg[AD9910_REG_CFR2].val32); + + pwm_init_state(st->drctl_pwm, &state); + + if (!ndh && ndl) { + state.duty_cycle =3D st->ramp_down_time_ns / 2; + state.period =3D st->ramp_down_time_ns; + state.polarity =3D PWM_POLARITY_INVERSED; + } else if (ndh && !ndl) { + state.duty_cycle =3D st->ramp_up_time_ns / 2; + state.period =3D st->ramp_up_time_ns; + state.polarity =3D PWM_POLARITY_NORMAL; + } else if (!ndh && !ndl) { + state.duty_cycle =3D st->ramp_up_time_ns; + state.period =3D st->ramp_up_time_ns + st->ramp_down_time_ns; + state.polarity =3D PWM_POLARITY_NORMAL; + } else { + state.duty_cycle =3D 0; + state.period =3D st->ramp_up_time_ns + st->ramp_down_time_ns; + state.polarity =3D PWM_POLARITY_NORMAL; + } + + if (!state.period) { + pwm_disable(st->drctl_pwm); + return 0; + } + + state.enabled =3D true; + ret =3D pwm_apply_might_sleep(st->drctl_pwm, &state); + if (ret) + return ret; + + ret =3D pwm_get_state_hw(st->drctl_pwm, &state); + if (ret) + return ret; + + if (!ndh && ndl) { + st->ramp_down_time_ns =3D state.period; + } else if (ndh && !ndl) { + st->ramp_up_time_ns =3D state.period; + } else if (!ndh && !ndl) { + st->ramp_up_time_ns =3D state.duty_cycle; + st->ramp_down_time_ns =3D state.period - st->ramp_up_time_ns; + } + + return 0; +} + static ssize_t ad9910_ext_info_read(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, @@ -675,6 +740,13 @@ static ssize_t ad9910_ext_info_write(struct iio_dev *i= ndio_dev, if (ret) return ret; } + + /* + * DRCTL waveform depends on the dwell configuration, but the + * previous integration time values may not suit the new + * waveform, which should not prevent dwell_en from changing. + */ + ad9910_drctl_sync(st); break; default: return -EINVAL; @@ -1054,7 +1126,8 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .channel =3D AD9910_CHANNEL_DRG_RAMP_UP, .address =3D AD9910_CHAN_IDX_DRG_FREQ_RAMP_UP, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_INT_TIME), .ext_info =3D ad9910_drg_ramp_ext_info, .parent =3D &ad9910_channels[AD9910_CHAN_IDX_DRG_FREQ], }, @@ -1065,7 +1138,8 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .channel =3D AD9910_CHANNEL_DRG_RAMP_DOWN, .address =3D AD9910_CHAN_IDX_DRG_FREQ_RAMP_DOWN, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_INT_TIME), .ext_info =3D ad9910_drg_ramp_ext_info, .parent =3D &ad9910_channels[AD9910_CHAN_IDX_DRG_FREQ], }, @@ -1076,7 +1150,8 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .channel =3D AD9910_CHANNEL_DRG_RAMP_UP, .address =3D AD9910_CHAN_IDX_DRG_PHASE_RAMP_UP, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_INT_TIME), .ext_info =3D ad9910_drg_ramp_ext_info, .parent =3D &ad9910_channels[AD9910_CHAN_IDX_DRG_PHASE], }, @@ -1087,7 +1162,8 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .channel =3D AD9910_CHANNEL_DRG_RAMP_DOWN, .address =3D AD9910_CHAN_IDX_DRG_PHASE_RAMP_DOWN, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_INT_TIME), .ext_info =3D ad9910_drg_ramp_ext_info, .parent =3D &ad9910_channels[AD9910_CHAN_IDX_DRG_PHASE], }, @@ -1098,7 +1174,8 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .channel =3D AD9910_CHANNEL_DRG_RAMP_UP, .address =3D AD9910_CHAN_IDX_DRG_AMP_RAMP_UP, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_INT_TIME), .ext_info =3D ad9910_drg_ramp_ext_info, .parent =3D &ad9910_channels[AD9910_CHAN_IDX_DRG_AMP], }, @@ -1109,7 +1186,8 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .channel =3D AD9910_CHANNEL_DRG_RAMP_DOWN, .address =3D AD9910_CHAN_IDX_DRG_AMP_RAMP_DOWN, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_INT_TIME), .ext_info =3D ad9910_drg_ramp_ext_info, .parent =3D &ad9910_channels[AD9910_CHAN_IDX_DRG_AMP], }, @@ -1337,6 +1415,17 @@ static int ad9910_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } + case IIO_CHAN_INFO_INT_TIME: + switch (chan->channel) { + case AD9910_CHANNEL_DRG_RAMP_UP: + iio_val_s64_decompose(st->ramp_up_time_ns, val, val2); + return IIO_VAL_DECIMAL64_NANO; + case AD9910_CHANNEL_DRG_RAMP_DOWN: + iio_val_s64_decompose(st->ramp_down_time_ns, val, val2); + return IIO_VAL_DECIMAL64_NANO; + default: + return -EINVAL; + } default: return -EINVAL; } @@ -1637,6 +1726,26 @@ static int ad9910_write_raw(struct iio_dev *indio_de= v, return -EINVAL; } } + case IIO_CHAN_INFO_INT_TIME: { + s64 val64 =3D iio_val_s64_compose(val, val2); + + if (!st->drctl_pwm) + return -EOPNOTSUPP; + if (val64 < 0) + return -EINVAL; + + switch (chan->channel) { + case AD9910_CHANNEL_DRG_RAMP_UP: + st->ramp_up_time_ns =3D val64; + break; + case AD9910_CHANNEL_DRG_RAMP_DOWN: + st->ramp_down_time_ns =3D val64; + break; + default: + return -EINVAL; + } + return ad9910_drctl_sync(st); + } default: return -EINVAL; } @@ -1671,6 +1780,8 @@ static int ad9910_write_raw_get_fmt(struct iio_dev *i= ndio_dev, return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_OFFSET: return IIO_VAL_DECIMAL64_MICRO; + case IIO_CHAN_INFO_INT_TIME: + return IIO_VAL_DECIMAL64_NANO; default: return -EINVAL; } @@ -2249,6 +2360,15 @@ static int ad9910_probe(struct spi_device *spi) =20 fsleep(AD9910_WAKEUP_DELAY_us); =20 + st->drctl_pwm =3D devm_pwm_get(dev, "drctl"); + if (IS_ERR(st->drctl_pwm)) { + ret =3D PTR_ERR(st->drctl_pwm); + if (ret !=3D -ENOENT && ret !=3D -ENODEV) + return dev_err_probe(dev, PTR_ERR(st->drctl_pwm), + "failed to get drctl pwm\n"); + st->drctl_pwm =3D NULL; + } + ret =3D ad9910_parse_fw(st); if (ret) return ret; --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 E9C3754A7D0; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082996; cv=none; b=DOpCg4fvhH8gl5Tbt4nTT0nciqsSBr6dCs+kPujaWDGuYS5XXeayL7ZM28HiqvLXCSeHGqvE8BNi3Zv+FdbsulgmlZv//E+UPdVFYPbMGwwq6exUoG3fTszFIQXBFv8N8GVfG9isTZyjYRZFEEkGFeJ/YTxNi7Ei3nQeq6pNFrc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082996; c=relaxed/simple; bh=Nq/bhIY+1pN2Catq+rqdm8EhgvLeHFajh+ES2Vz/HXE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tp/H0HKw7FaHIPvgRCbDQM5ycMgipft+rU0WoPcrNAANwdbH9RAGxMonLZk6wZ/gTutuCBWcE9rZuqOrDz1ONxtuM+K9X4sw0k2jpTDWslCWRxCq9jXIiyPPTHDUjFuqFyRyM/GVsCgnj7A5aXoDupRsxlEuzGGi9zmOY2Om0BQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MdyizAsI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MdyizAsI" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3F9D8C4AF11; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=Nq/bhIY+1pN2Catq+rqdm8EhgvLeHFajh+ES2Vz/HXE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=MdyizAsIp+AeENSxDpZ/qR964OnZkVWfSLQwEbxeP4kvakYZChCiA2mt20wmwXXMb bEhM7F9LLMtWfM2WRSE39IgOIzy3k5Liq6SVdIYuaFpoSV9/mZ5UM6ZXJYjq2c8vYG M3qXBXxVtjc6epVLUcHGLYNdwUrMcY3qZT59rKaEElD+Rx20PRxnIRwPh4AFqmSdMt 8VsT+c4KqDZmN9rvje8L4vsdjqoMvBmV1rdYAniUE9B3Ppo+rRJziACm3zj/yy7Rs7 BDys45TjCw/zNAOAKEvALY//FDU//XvRecsuWNckeTkr3IcgMV6xIGDQV7AzjkJPOq HyIc+3KIWFG2g== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2B77DCCA464; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:48 -0300 Subject: [PATCH 08/10] iio: frequency: ad9910: support iio backend 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 Message-Id: <20261015-ad9910-backend-support-v1-8-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=17762; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=P3p6O7BPPm0xM0t+cQXxnAtC356E/y9VGIItaRf5Jio=; b=2JD1Vk2ih7tQUG2b0n6l9onQuC1aCD5eMpryRlqLm+pc5ygz3bMzoj1T/veo6AfuXioFftGtR LUOS3LGpUgsBaHh34L0KDO9c6jvZ8BMF59TUJuTeMuVxnV1g4J68qiD X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar The AD9910 parallel data port allows modulation of the DDS core parameters at up to the PDCLK rate, which requires a high-speed data source. Add support for an optional IIO backend that provides such interface, with data streamed into the device through an output buffer. The parallel port channels get scan indexes and scan types according to the data destination: 14-bit amplitude, 16-bit phase, 16-bit frequency, or the 8-bit amplitude and phase pair for polar modulation. As only one destination can be active at a time, this is enforced by the available scan masks. On buffer enable, the destination is configured in the backend and the parallel data port is enabled. The sampling_frequency attribute of the parallel port channels controls the backend data rate. The backend is also notified about profile changes, as it may drive the PROFILE[2:0] pins, and the debugfs source attributes now consider the parallel data port when reporting which channel controls each DDS core parameter. Signed-off-by: Rodrigo Alencar --- drivers/iio/frequency/Kconfig | 1 + drivers/iio/frequency/ad9910.c | 215 +++++++++++++++++++++++++++++++++++++= ++-- 2 files changed, 210 insertions(+), 6 deletions(-) diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index f7f5c3cce005..8480076c779f 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -32,6 +32,7 @@ config AD9910 select CRC32 select FW_LOADER select FW_UPLOAD + select IIO_BACKEND help Say yes here to build support for Analog Devices AD9910 1 GSPS, 14-Bit DDS with integrated DAC. diff --git a/drivers/iio/frequency/ad9910.c b/drivers/iio/frequency/ad9910.c index 3d517879dee3..39d65dafd5a1 100644 --- a/drivers/iio/frequency/ad9910.c +++ b/drivers/iio/frequency/ad9910.c @@ -31,6 +31,7 @@ #include #include =20 +#include #include #include =20 @@ -300,6 +301,15 @@ struct ad9910_ram_fw { __be32 words[] __counted_by_be(wcount); } __packed; =20 +enum { + AD9910_SCAN_IDX_AMP =3D 0, + AD9910_SCAN_IDX_PHASE, + AD9910_SCAN_IDX_FREQ, + /* polar phase goes first, as it is placed in the lower byte, D[7:0] */ + AD9910_SCAN_IDX_POLAR_PHASE, + AD9910_SCAN_IDX_POLAR_AMP, +}; + enum { AD9910_POWERDOWN, AD9910_DWELL_EN, @@ -331,6 +341,7 @@ struct ad9910_state { struct gpio_desc *gpio_pwdown; struct gpio_desc *gpio_update; struct gpio_descs *gpio_profile; + struct iio_backend *back; =20 s64 ramp_up_time_ns; s64 ramp_down_time_ns; @@ -350,6 +361,7 @@ struct ad9910_state { =20 struct ad9910_data data; u8 profile; + u8 scan_mask; =20 bool ram_fwu_cancel; char ram_fwu_name[20]; @@ -568,6 +580,11 @@ static int ad9910_set_sysclk_freq(struct ad9910_state = *st, u32 freq_hz, =20 st->data.sysclk_freq_hz =3D sysclk_freq_hz; =20 + if (st->back) + return iio_backend_set_sampling_freq(st->back, + AD9910_CHAN_IDX_PHY, + sysclk_freq_hz); + return 0; } =20 @@ -579,6 +596,10 @@ static int ad9910_profile_set(struct ad9910_state *st,= u8 profile) values[0] =3D profile; gpiod_multi_set_value_cansleep(st->gpio_profile, values); =20 + if (st->back) + return iio_backend_chan_enable(st->back, + AD9910_CHAN_IDX_PROFILE_0 + profile); + return 0; } =20 @@ -1016,6 +1037,7 @@ static const struct iio_chan_spec_ext_info ad9910_osk= _ext_info[] =3D { .output =3D 1, \ .channel =3D AD9910_CHANNEL_PROFILE_ ## idx, \ .address =3D AD9910_CHAN_IDX_PROFILE_ ## idx, \ + .scan_index =3D -1, \ .info_mask_separate =3D BIT(IIO_CHAN_INFO_ENABLE) | \ BIT(IIO_CHAN_INFO_FREQUENCY) | \ BIT(IIO_CHAN_INFO_PHASE) | \ @@ -1030,6 +1052,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_PHY, .address =3D AD9910_CHAN_IDX_PHY, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE), .ext_info =3D ad9910_phy_ext_info, @@ -1048,6 +1071,14 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_PARALLEL, .address =3D AD9910_CHAN_IDX_PARALLEL_AMP, + .scan_index =3D AD9910_SCAN_IDX_AMP, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 14, + .storagebits =3D 16, + .shift =3D 2, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], }, [AD9910_CHAN_IDX_PARALLEL_PHASE] =3D { @@ -1056,7 +1087,15 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_PARALLEL, .address =3D AD9910_CHAN_IDX_PARALLEL_PHASE, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_SCALE), + .scan_index =3D AD9910_SCAN_IDX_PHASE, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 16, + .storagebits =3D 16, + .shift =3D 0, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], }, [AD9910_CHAN_IDX_PARALLEL_FREQ] =3D { @@ -1065,7 +1104,15 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_PARALLEL, .address =3D AD9910_CHAN_IDX_PARALLEL_FREQ, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_OFFSET) | + .scan_index =3D AD9910_SCAN_IDX_FREQ, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 16, + .storagebits =3D 16, + .shift =3D 0, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], }, @@ -1075,7 +1122,15 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_PARALLEL_POLAR, .address =3D AD9910_CHAN_IDX_PARALLEL_POLAR_AMP, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_OFFSET) | + .scan_index =3D AD9910_SCAN_IDX_POLAR_AMP, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 8, + .storagebits =3D 8, + .shift =3D 0, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], }, @@ -1085,7 +1140,15 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_PARALLEL_POLAR, .address =3D AD9910_CHAN_IDX_PARALLEL_POLAR_PHASE, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_OFFSET) | + .scan_index =3D AD9910_SCAN_IDX_POLAR_PHASE, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 8, + .storagebits =3D 8, + .shift =3D 0, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], }, @@ -1095,6 +1158,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG, .address =3D AD9910_CHAN_IDX_DRG_FREQ, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], @@ -1105,6 +1169,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG, .address =3D AD9910_CHAN_IDX_DRG_PHASE, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], @@ -1115,6 +1180,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG, .address =3D AD9910_CHAN_IDX_DRG_AMP, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), .parent =3D &ad9910_channels[AD9910_CHAN_IDX_PHY], @@ -1125,6 +1191,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG_RAMP_UP, .address =3D AD9910_CHAN_IDX_DRG_FREQ_RAMP_UP, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_INT_TIME), @@ -1137,6 +1204,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG_RAMP_DOWN, .address =3D AD9910_CHAN_IDX_DRG_FREQ_RAMP_DOWN, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_INT_TIME), @@ -1149,6 +1217,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG_RAMP_UP, .address =3D AD9910_CHAN_IDX_DRG_PHASE_RAMP_UP, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_INT_TIME), @@ -1161,6 +1230,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG_RAMP_DOWN, .address =3D AD9910_CHAN_IDX_DRG_PHASE_RAMP_DOWN, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_INT_TIME), @@ -1173,6 +1243,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG_RAMP_UP, .address =3D AD9910_CHAN_IDX_DRG_AMP_RAMP_UP, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_INT_TIME), @@ -1185,6 +1256,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_DRG_RAMP_DOWN, .address =3D AD9910_CHAN_IDX_DRG_AMP_RAMP_DOWN, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_INT_TIME), @@ -1197,6 +1269,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_RAM, .address =3D AD9910_CHAN_IDX_RAM, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_FREQUENCY) | BIT(IIO_CHAN_INFO_PHASE) | @@ -1209,6 +1282,7 @@ static const struct iio_chan_spec ad9910_channels[] = =3D { .output =3D 1, .channel =3D AD9910_CHANNEL_OSK, .address =3D AD9910_CHAN_IDX_OSK, + .scan_index =3D -1, .info_mask_separate =3D BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ), @@ -1322,6 +1396,12 @@ static int ad9910_read_raw(struct iio_dev *indio_dev, case AD9910_CHANNEL_PHY: *val =3D st->data.sysclk_freq_hz; return IIO_VAL_INT; + case AD9910_CHANNEL_PARALLEL: + case AD9910_CHANNEL_PARALLEL_POLAR: + if (!st->back) + return -EOPNOTSUPP; + + return iio_backend_read_raw(st->back, chan, val, val2, info); case AD9910_CHANNEL_DRG_RAMP_UP: tmp32 =3D FIELD_GET(AD9910_DRG_RATE_INC_MSK, st->reg[AD9910_REG_DRG_RATE].val32); @@ -1631,6 +1711,17 @@ static int ad9910_write_raw(struct iio_dev *indio_de= v, if (chan->channel =3D=3D AD9910_CHANNEL_PHY) return ad9910_set_sysclk_freq(st, val, true); =20 + if (chan->channel =3D=3D AD9910_CHANNEL_PARALLEL || + chan->channel =3D=3D AD9910_CHANNEL_PARALLEL_POLAR) { + if (!st->back) + return -EOPNOTSUPP; + if (val < 0) + return -EINVAL; + + return iio_backend_set_sampling_freq(st->back, + chan->address, val); + } + if (val < 0 || val2 < 0 || val > st->data.sysclk_freq_hz / 4) return -EINVAL; =20 @@ -1773,9 +1864,14 @@ static int ad9910_write_raw_get_fmt(struct iio_dev *= indio_dev, return -EINVAL; } case IIO_CHAN_INFO_SAMP_FREQ: - if (chan->channel =3D=3D AD9910_CHANNEL_PHY) + switch (chan->channel) { + case AD9910_CHANNEL_PHY: + case AD9910_CHANNEL_PARALLEL: + case AD9910_CHANNEL_PARALLEL_POLAR: return IIO_VAL_INT; - return IIO_VAL_INT_PLUS_MICRO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } case IIO_CHAN_INFO_SCALE: return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_OFFSET: @@ -2164,6 +2260,12 @@ static inline const char *ad9910_frequency_source_ge= t(struct ad9910_state *st) st->reg[AD9910_REG_CFR2].val32)) return ad9910_channel_str[AD9910_CHAN_IDX_DRG_FREQ]; =20 + /* Parallel data port enabled and data destination is frequency */ + mode_en =3D FIELD_GET(AD9910_CFR2_PARALLEL_DATA_PORT_EN_MSK, + st->reg[AD9910_REG_CFR2].val32); + if (mode_en && (st->scan_mask & BIT(AD9910_SCAN_IDX_FREQ))) + return ad9910_channel_str[AD9910_CHAN_IDX_PARALLEL_FREQ]; + /* FTW: RAM enabled and data destination is phase, amplitude, or polar */ if (ram_en) return ad9910_channel_str[AD9910_CHAN_IDX_RAM]; @@ -2204,6 +2306,16 @@ static inline const char *ad9910_phase_source_get(st= ruct ad9910_state *st) st->reg[AD9910_REG_CFR2].val32)) return ad9910_channel_str[AD9910_CHAN_IDX_DRG_PHASE]; =20 + /* Parallel data port enabled and data destination is phase */ + mode_en =3D FIELD_GET(AD9910_CFR2_PARALLEL_DATA_PORT_EN_MSK, + st->reg[AD9910_REG_CFR2].val32); + if (mode_en) { + if (st->scan_mask & BIT(AD9910_SCAN_IDX_PHASE)) + return ad9910_channel_str[AD9910_CHAN_IDX_PARALLEL_PHASE]; + if (st->scan_mask & BIT(AD9910_SCAN_IDX_POLAR_PHASE)) + return ad9910_channel_str[AD9910_CHAN_IDX_PARALLEL_POLAR_PHASE]; + } + /* POW: RAM enabled and data destination is frequency or amplitude */ if (ram_en) return ad9910_channel_str[AD9910_CHAN_IDX_RAM]; @@ -2250,6 +2362,16 @@ static inline const char *ad9910_amplitude_source_ge= t(struct ad9910_state *st) st->reg[AD9910_REG_CFR2].val32)) return ad9910_channel_str[AD9910_CHAN_IDX_DRG_AMP]; =20 + /* Parallel data port enabled and data destination is amplitude */ + mode_en =3D FIELD_GET(AD9910_CFR2_PARALLEL_DATA_PORT_EN_MSK, + st->reg[AD9910_REG_CFR2].val32); + if (mode_en) { + if (st->scan_mask & BIT(AD9910_SCAN_IDX_AMP)) + return ad9910_channel_str[AD9910_CHAN_IDX_PARALLEL_AMP]; + if (st->scan_mask & BIT(AD9910_SCAN_IDX_POLAR_AMP)) + return ad9910_channel_str[AD9910_CHAN_IDX_PARALLEL_POLAR_AMP]; + } + /* only way to control amplitude at this point is through OSK */ if (ram_en) return ad9910_channel_str[AD9910_CHAN_IDX_OSK]; @@ -2278,6 +2400,72 @@ static inline void ad9910_debugfs_init(struct ad9910= _state *st, &ad9910_amplitude_source_fops); } =20 +static const u8 ad9910_scan_chan_idx[] =3D { + [AD9910_SCAN_IDX_AMP] =3D AD9910_CHAN_IDX_PARALLEL_AMP, + [AD9910_SCAN_IDX_PHASE] =3D AD9910_CHAN_IDX_PARALLEL_PHASE, + [AD9910_SCAN_IDX_FREQ] =3D AD9910_CHAN_IDX_PARALLEL_FREQ, + [AD9910_SCAN_IDX_POLAR_PHASE] =3D AD9910_CHAN_IDX_PARALLEL_POLAR_PHASE, + [AD9910_SCAN_IDX_POLAR_AMP] =3D AD9910_CHAN_IDX_PARALLEL_POLAR_AMP, +}; + +static u32 ad9910_buffer_chan_idx(struct iio_dev *indio_dev) +{ + unsigned int scan_idx =3D find_first_bit(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + + return ad9910_scan_chan_idx[scan_idx]; +} + +static int ad9910_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad9910_state *st =3D iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + st->scan_mask =3D *indio_dev->active_scan_mask; + ret =3D iio_backend_chan_enable(st->back, + ad9910_buffer_chan_idx(indio_dev)); + if (ret) + return ret; + + return ad9910_reg32_update(st, AD9910_REG_CFR2, + AD9910_CFR2_PARALLEL_DATA_PORT_EN_MSK, + AD9910_CFR2_PARALLEL_DATA_PORT_EN_MSK, + true); +} + +static int ad9910_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad9910_state *st =3D iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + st->scan_mask =3D 0; + ret =3D ad9910_reg32_update(st, AD9910_REG_CFR2, + AD9910_CFR2_PARALLEL_DATA_PORT_EN_MSK, + 0, true); + if (ret) + return ret; + + return iio_backend_chan_disable(st->back, + ad9910_buffer_chan_idx(indio_dev)); +} + +static const struct iio_buffer_setup_ops ad9910_buffer_setup_ops =3D { + .preenable =3D ad9910_buffer_preenable, + .postdisable =3D ad9910_buffer_postdisable, +}; + +static const unsigned long ad9910_available_scan_masks[] =3D { + BIT(AD9910_SCAN_IDX_AMP), + BIT(AD9910_SCAN_IDX_PHASE), + BIT(AD9910_SCAN_IDX_FREQ), + BIT(AD9910_SCAN_IDX_POLAR_AMP) | BIT(AD9910_SCAN_IDX_POLAR_PHASE), + 0 +}; + static int ad9910_probe(struct spi_device *spi) { static const char * const supplies[] =3D { @@ -2321,6 +2509,20 @@ static int ad9910_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(dev_rst), "failed to get device reset control\n"); =20 + st->back =3D devm_iio_backend_get_optional(dev, NULL); + if (IS_ERR(st->back)) + return dev_err_probe(dev, PTR_ERR(st->back), + "failed to get iio backend\n"); + if (st->back) { + ret =3D devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "failed to request iio backend buffer\n"); + + indio_dev->setup_ops =3D &ad9910_buffer_setup_ops; + indio_dev->available_scan_masks =3D ad9910_available_scan_masks; + } + /* * The IO RESET pin is not used in this driver, as we assume that all * SPI transfers are complete, but if it is wired up, we need to make @@ -2424,3 +2626,4 @@ module_spi_driver(ad9910_driver); MODULE_AUTHOR("Rodrigo Alencar "); MODULE_DESCRIPTION("Analog Devices AD9910 DDS driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BACKEND"); --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B3540545D85; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; cv=none; b=Z8SO2S0JbsL4xr7VzEoM3Nrsu8vdc8zNIa6N37XD1ECvJ4FLzyKchB30IIoZPb5dP4ROMQNrHql490snH5mM1Mf76054SgcbPQgg2HyUNss99D+XEyiKXOng9iknx7N57AJyCLIlQI7tiRmZAYLW475eSjsUi8y1YkPrnfEnQ1s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082995; c=relaxed/simple; bh=SnU0DT/RjXLJbopdxpaOnyfW6SnaewFBaST4OCO0iI0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=A9qh9VlS2zkN3C5z8edC7JqwyXuovhYT0+YK8jWkQiRdf67fJbVsb2itz3ExwT+I6Fe+vuXAH469vgjTdOMKbtvJApHZDUlcaU2DjK+yLknmZ5aiwCZ5GfjzTtxTPtJQK9Jn4WpcejHB8dZvgguGT1fSaq1UvcetoMj+zXk1UXM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L5fU8/zX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L5fU8/zX" Received: by smtp.kernel.org (Postfix) with ESMTPS id 4D87DC4AF0D; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=SnU0DT/RjXLJbopdxpaOnyfW6SnaewFBaST4OCO0iI0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=L5fU8/zXG/IqJMo5mOaCvxXFGgGyPxtLwiloB2UvqqRDEji8kCw+B9aQ+YS2e6OSL USqj+hY+1pUE+WUnPynjHi/wB7k6UiCB2M8sU2xogZe17H+DrMFQ/oq6XuJw/ggbaq GpCkvMi9MDkAO75/oF+JhXJSFOKTllG0D+5UyT8mr4oab27ffeujFCugF86wsXX08o sfDPTC82WnflgmsGZM/sy8O8GZdh+ed2K0J+Sho2d082P5KOqnZTXihkz8W0a7ssUK Tg/jZsc9d/7OwHp1nRia3ScMegtm9xTdQjZ9/Yw49aVXlCmiOPF7eaviukL6xiYFMz veF3ogCG7khIA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A8A0CC6B38; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:49 -0300 Subject: [PATCH 09/10] iio: ABI: add integration_time for output channels 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 Message-Id: <20261015-ad9910-backend-support-v1-9-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=1995; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=IoK+rS/AZpKcfckFDfvILHdHeYT/QobUUWmOhvEtSTA=; b=Mr5vQFQlwKKy+y9gy8vISksfEGtOjpmByK+zUfotprSp5IkhDdmGDFnwNYqLDX2gnY6yRr/v5 Jp1ZhkCb/kxCKImrY+JD9r0PACi3QKTqLic3rPsXD5I0ZXx0EIEP0t3 X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar Document the integration_time attribute for output channels, which is the time interval during which the output is generated by integrating a quantity, such as its rate of change. It is the output counterpart of the integration_time already defined for input channels. Add entries for the altcurrent, frequency and phase channel types, which are going to be used by the AD9910 DDS driver. Signed-off-by: Rodrigo Alencar Reviewed-by: Nuno S=C3=A1 --- Documentation/ABI/testing/sysfs-bus-iio | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/te= sting/sysfs-bus-iio index 2b6f57041763..a41a96935cfb 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1744,6 +1744,23 @@ Description: seconds. If shared across all channels of a given type, _integration_time is used. =20 +What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_integration_time +What: /sys/bus/iio/devices/iio:deviceX/out_frequencyY_integration_time +What: /sys/bus/iio/devices/iio:deviceX/out_phaseY_integration_time +KernelVersion: 7.4 +Contact: linux-iio@vger.kernel.org +Description: + This attribute is used to get/set the integration time in + seconds of an output channel, i.e., the time interval during + which the output is generated by integrating (accumulating) a + quantity over time, such as the rate of change (roc) of the + channel. The output variation over this interval corresponds to + the integral of that quantity, which may be bounded by limits + configured through other channel attributes. The written value + may be adjusted to the nearest interval supported by the + hardware. If shared across all channels of a given type, + _integration_time is used. + What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org --=20 2.43.0 From nobody Fri Oct 23 22:16:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D6C14548554; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082996; cv=none; b=cBsB4KsviuvTy+AUsAUa5Ez0Hj1QA4G9L9TZ05Wf4Pz5nylK6fz3pEjXBWMzPvnx7Yx3nrfqu/iI3ELhw1DtbxEYvkKj+LHLZqvMDBAilZ0wMJNALE+nBIWnggj8im0oBX3KihTXZGlHQ0W5Je9xlfv/5YQBdVq2OOeLFq2H3E4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792082996; c=relaxed/simple; bh=UELqeIQMLribOGV8awN5nOAA+BGfrVwbtmkojR88hVg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DokMXHAy3UGLycNejRy9EAZgw4FFSj/XJAabQFyAjSuYs9WInEpBFygfuWuddvrQuxDk6R1stlrED/JODI57dGVmFYfFLKXaXlSRPqZ7QUb0A4htt4y/R7TbmsAD/H1okCz4HMaQEuTxr96qp4WNmANdIhr4T+tyBh+xC5rrqos= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Wtajyma8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Wtajyma8" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5CBF4C2BCF4; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1792082995; bh=UELqeIQMLribOGV8awN5nOAA+BGfrVwbtmkojR88hVg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Wtajyma8TMGo9W5vs/e5qSE7bBmoFhyHR51f8akR+z3Jx52pcY42YYTa7nAM7115z Xyjg7ibqA1hZvhgpHCZO1LCVV/khOH2D74TfMtRretAZboZ0k+9QYMRUoYG06cPixp m70udQNaOPd9z1NyFO9/3imxnJB1M9PyTnxxEUq84rZ8ybtk94y61o2i4R9Y1MJ3jE ekPNUfxNWl8h+Yk5UfqYUxYfo7MUlUkG9AlQFTsg4XOBMqoTWwouN4Wi/h2PcA4MSU C9zxcZl/jWJiuctchSRUG8NABqopAIGSsc0369oz0fNavAEyH6Xpgo2O9kOrE5Bqma E7J2Ihtfw0rUw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A81FCC6B39; Thu, 15 Oct 2026 16:49:55 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Thu, 15 Oct 2026 13:49:50 -0300 Subject: [PATCH 10/10] docs: iio: ad9910: document DRCTL pin control 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 Message-Id: <20261015-ad9910-backend-support-v1-10-3c21648c8e26@analog.com> References: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> In-Reply-To: <20261015-ad9910-backend-support-v1-0-3c21648c8e26@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux@analog.com, devicetree@vger.kernel.org, linux-pwm@vger.kernel.org, linux-doc@vger.kernel.org, Jonathan Cameron Cc: Olivier Moysan , Jonathan Cameron , David Lechner , Andy Shevchenko , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jonathan Corbet , Shuah Khan , Randy Dunlap , Rodrigo Alencar X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1792082993; l=6219; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=9AdEqIZ+bYqk9Lw6P7OuqM0LPTI0z5xHBJLcZX+ImKY=; b=iEB0Y0PLticdgwYdAAxIokYTL7YY0uahxuWGbnuUTbq7d067PpbmhYNaQYCaEVqF2iBpSxjO4 fr0brdPY/RZBnmGlAv1b0geUbVjekTb1BEcpQ6kE81EU8ieL+j0zvgz X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar Document the integration_time attribute of the digital ramp generator (DRG) rising and falling channels, and describe how the DRCTL pin waveform is generated from those values according to the dwell_en configuration. Add usage examples for triangular and sawtooth sweeps driven through the DRCTL pin. Signed-off-by: Rodrigo Alencar --- Documentation/iio/ad9910.rst | 90 ++++++++++++++++++++++++++++++++++++++++= +--- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/Documentation/iio/ad9910.rst b/Documentation/iio/ad9910.rst index aab569f561db..bff55cca8c82 100644 --- a/Documentation/iio/ad9910.rst +++ b/Documentation/iio/ad9910.rst @@ -85,13 +85,13 @@ system clock (SYSCLK) which affects all other channels. - ``drg_rising_frequency`` - ``drg_frequency`` - DRG frequency rising-ramp parameters: limit code, dwell enable, - ramp clock, rate of change. + ramp clock, rate of change, integration time. =20 * - ``out_frequency132`` - ``drg_falling_frequency`` - ``drg_frequency`` - DRG frequency falling-ramp parameters: limit code, dwell enable, - ramp clock, rate of change. + ramp clock, rate of change, integration time. =20 * - ``out_phase130`` - ``drg_phase`` @@ -104,13 +104,13 @@ system clock (SYSCLK) which affects all other channel= s. - ``drg_rising_phase`` - ``drg_phase`` - DRG phase rising-ramp parameters: limit code, dwell enable, ramp cl= ock, - rate of change. + rate of change, integration time. =20 * - ``out_phase132`` - ``drg_falling_phase`` - ``drg_phase`` - DRG phase falling-ramp parameters: limit code, dwell enable, ramp c= lock, - rate of change. + rate of change, integration time. =20 * - ``out_altcurrent130`` - ``drg_amplitude`` @@ -123,13 +123,13 @@ system clock (SYSCLK) which affects all other channel= s. - ``drg_rising_amplitude`` - ``drg_amplitude`` - DRG amplitude rising-ramp parameters: limit code, dwell enable, - ramp clock, rate of change. + ramp clock, rate of change, integration time. =20 * - ``out_altcurrent132`` - ``drg_falling_amplitude`` - ``drg_amplitude`` - DRG amplitude falling-ramp parameters: limit code, dwell enable, - ramp clock, rate of change. + ramp clock, rate of change, integration time. =20 * - ``out_altcurrent140`` - ``ram`` @@ -493,6 +493,60 @@ Ramp channel attributes from the hardware step size and the current ramp clock. Writing requires ``sampling_frequency`` to be configured first. =20 + * - ``integration_time`` + - s + - Time interval assigned to the ramp direction, which is used to gene= rate + the DRCTL pin waveform. See `DRCTL pin control`_. Rising and falling + ramp channels of all destinations share the same underlying value f= or + their respective directions. The written value is adjusted to the + resolution supported by the PWM provider. + +DRCTL pin control +^^^^^^^^^^^^^^^^^ + +The DRCTL pin selects the DRG slope direction: a logic high drives the ramp +towards the upper limit and a logic low drives it towards the lower limit. +When a PWM is assigned to the DRCTL pin (via the ``pwms`` and ``pwm-names`` +devicetree properties), the driver generates the DRCTL waveform from the +``integration_time`` of the rising and falling ramp channels, according to= the +``dwell_en`` configuration: + +.. flat-table:: + :header-rows: 1 + + * - Rising ``dwell_en`` + - Falling ``dwell_en`` + - DRCTL waveform + + * - 1 + - 1 + - DRCTL is held high for the rising ``integration_time`` and then held + low for the falling ``integration_time``. The PWM period is the sum= of + both intervals. If a ramp reaches its limit before its interval + elapses, the output dwells at that limit. + + * - 0 + - 1 + - Sawtooth rising ramp: a new ramp starts at every DRCTL rising edge, + which happens periodically at the rising ``integration_time``. The + falling ``integration_time`` is not used. + + * - 1 + - 0 + - Sawtooth falling ramp: a new ramp starts at every DRCTL falling edg= e, + which happens periodically at the falling ``integration_time``. The + rising ``integration_time`` is not used. + + * - 0 + - 0 + - Bidirectional continuous ramp. DRCTL is not relevant and it is held + low. + +The DRCTL output is disabled when the resulting PWM period is zero, e.g., = when +the relevant ``integration_time`` attributes are set to ``0``. Without a P= WM +assigned to the DRCTL pin, writing to ``integration_time`` fails with +``-EOPNOTSUPP``. + Usage examples ^^^^^^^^^^^^^^ =20 @@ -525,6 +579,30 @@ Configure a frequency sweep from 40 MHz to 60 MHz with= a rate of change of # Enable the DRG with frequency as the destination echo 1 > /sys/bus/iio/devices/iio\:device0/out_frequency130_en =20 +With the same limits and rate of change, each ramp takes 0.8 ms to complet= e. +Configure a PWM-driven triangular sweep that dwells 0.2 ms at each limit: + +.. code-block:: bash + + # Enable dwell on both limits, so DRCTL controls the ramp direction + echo 1 > /sys/bus/iio/devices/iio\:device0/out_frequency131_dwell_en + echo 1 > /sys/bus/iio/devices/iio\:device0/out_frequency132_dwell_en + + # DRCTL high for 1 ms (rising ramp) and low for 1 ms (falling ramp) + echo 0.001 > /sys/bus/iio/devices/iio\:device0/out_frequency131_integrat= ion_time + echo 0.001 > /sys/bus/iio/devices/iio\:device0/out_frequency132_integrat= ion_time + +Configure a rising sawtooth sweep that restarts every 1 ms: + +.. code-block:: bash + + # No dwell at the upper limit: the ramp returns to the lower limit + echo 0 > /sys/bus/iio/devices/iio\:device0/out_frequency131_dwell_en + echo 1 > /sys/bus/iio/devices/iio\:device0/out_frequency132_dwell_en + + # A new rising ramp starts every 1 ms + echo 0.001 > /sys/bus/iio/devices/iio\:device0/out_frequency131_integrat= ion_time + RAM mode -------- =20 --=20 2.43.0