From patchwork Fri Feb 16 14:10:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560070 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 9DA7512D766 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092689; cv=none; b=J6HmTDWf5Y5xxYeFYtcuoS6Z73ab867930qbMslZY2EmyZbDOO5ujXQz7NpvYSkGzbflnSBZrnaJxI1bAJfsaWrwqWBckwS8v25II93dYLbJAthABH6o7UncQF/FUvroJE+O5LQXN+QDvXoF0I/AcauOVnZYQXQKld0imf+7UHc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092689; c=relaxed/simple; bh=Tuo7/PzJzLX1SAtU3H5a7iHPPv2xWVJsxIzSubTHDc0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lbHa/b+NHL7/+6RQ6olAaOYkQPbIJrNBOO9eh6K5LrGb1oPPYifyAX8MCSi8NtBq31qfWXgLw+wNDEU6z2uiUclBJsFi5tHmFZXu24X2Zra5P24KhVBpwn3JOwo7+YiBhqCb09/ZBDEEwRfmzS0wRsVC0+h66KlbchiBkMzX604= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Rx7XXuFE; 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="Rx7XXuFE" Received: by smtp.kernel.org (Postfix) with ESMTPS id 40C51C433C7; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=Tuo7/PzJzLX1SAtU3H5a7iHPPv2xWVJsxIzSubTHDc0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Rx7XXuFE04kDAZ8vvEuAUz7eZL+oEnchZBZ4lPpYwhttmQV4IcTnjcUPmpIW4IC5d zrjWjYXBvFP3S8Xw+Uz/RhpGFLp5RrVsw+jPMiohRiaUyobUBPIY8Jqa1ATOsaxD94 TH4ZNDGWNhxPDoUnf8hm3LOyRzWLGkDzl0r2lD8/TVMzxCdoMqNxV+Sfu5Hf/Aot7N u2HsTjMRJyfVoP/hnCHvV0nPsqVQ3QfZF93bWsKQ3fyw7YX7+g1YkzZVDNVv0DcR6Y SJW+Q7t5bsJbSaAKzuvWMDxwqBEB5z5cJZp0dn1hKxCKZqmPPbfdW4li1fsT28ipCY jOtW8ZqrX+JGg== 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 259FEC48BEF; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:50 +0100 Subject: [PATCH RFC 1/8] iio: buffer: add function to set the buffer direction Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-1-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=1611; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=d5nwu7cwhkLNuXvBJXa201xpcbfgCUn83k0KuJDTwTA=; b=dH8M5t6AQdheCgW+ZjeT64oYXmXSOk26zy2dis9MriSL43KUs8exshkx4Hv8SqTJj5GKS9q1R TD6ZvxI9EdEAj53s/1coK2NEEg7opqVp+VcbghvzeUauHMSOk7OxsO9 X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Nuno Sa Add an helper function to set the direction. This is preliminary change and will be useful for IIO backends that provide output buffers. Signed-off-by: Nuno Sa --- drivers/iio/industrialio-buffer.c | 12 ++++++++++++ include/linux/iio/buffer.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index b581a7e80566..504e5a96bd90 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1982,6 +1982,18 @@ void iio_buffer_put(struct iio_buffer *buffer) } EXPORT_SYMBOL_GPL(iio_buffer_put); +/** + * iio_buffer_set_dir() - Set the buffer direction + * @buffer: The buffer to set the direction + * @direction: The direction + */ +void iio_buffer_set_dir(struct iio_buffer *buffer, + enum iio_buffer_direction direction) +{ + buffer->direction = direction; +} +EXPORT_SYMBOL(iio_buffer_set_dir); + /** * iio_device_attach_buffer - Attach a buffer to a IIO device * @indio_dev: The device the buffer should be attached to diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 418b1307d3f2..aee52b834443 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -55,4 +55,7 @@ bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, int iio_device_attach_buffer(struct iio_dev *indio_dev, struct iio_buffer *buffer); +void iio_buffer_set_dir(struct iio_buffer *buffer, + enum iio_buffer_direction direction); + #endif /* _IIO_BUFFER_GENERIC_H_ */ From patchwork Fri Feb 16 14:10:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560072 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 9DA3512D74F for ; Fri, 16 Feb 2024 14:11:29 +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=1708092689; cv=none; b=k2pheHCIEyq11tJO7BpOtQuFHMYSw/yY3RXk0FsNzu6n3oiwH6Syt3nKeUxPjVr5uQ4p55MEyj1rVDw6JjQ8+e26sGLmOwlCE8k038++092hqxLAuvtOHmFdCfRcN1iMLV7L22CXuZFCJeBVBuAsw7GQitSdNnYYva8XOetqIe0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092689; c=relaxed/simple; bh=32TOGugcvJJh6gm/zGxiRehdrYkiYLBiQNgo6DdJJ0s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QNGH6tB+hQt64BQ9/w3/+ObQWATU2kZcwjwQs4lyEqbTenPKgcX5uZTl6ShBQjebZZ/GAEwrG0fGvF+GCkxY7T1OYpwbcoktwCedKCOvTBLhH+ZxlgQurY47IFuY+MKzdrm0XHZZu4eHf4DspdkVqVhfZuDnqEaFJ5K/i4dDNWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OcUArK3b; 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="OcUArK3b" Received: by smtp.kernel.org (Postfix) with ESMTPS id 4A423C43394; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=32TOGugcvJJh6gm/zGxiRehdrYkiYLBiQNgo6DdJJ0s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=OcUArK3bAEEaorNSKXDw4At2P0c7hII+cJ1WCcocQVWKyIhMuQKYkX0t2OQUxuKpw CXj1hz4SHa06GqTiKpApPyJt4v6H2xf7zjrx+sxxdgIIyyKCWoMDrrClSgXuT7ZqBI SbCpz/QNGey2RbTYqPZC5VmGC3ahEMXYp2U8lPPnuCydyqT42oorBGO9hd8hjyXbEX YQBl1t54HbG41Tvh8P3TH2Yq7g2txYFYjCxtVTQZ4gv9waoY9B8OFTvHNxzx3FT/Zg PaN7R4dPs6dh4+ohwzEZKoXTwK9l+GDFT4DkmwrsuU0bnPBOjEg6aIJA8yiUPtNGnW iP4VEoWHPSiRw== 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 30C9CC48BC4; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:51 +0100 Subject: [PATCH RFC 2/8] iio: buffer-dma: Rename iio_dma_buffer_data_available() Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-2-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich , Paul Cercueil X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=3248; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=HpcxNkbUz45lD46m3e2kAC4KFbW46Vx9gXKUdmjhFZs=; b=YmhMLNRbwgTjtTILvJaNrZKrCYNqPFA+umVHFSwueBCHFQg83gc+ZB5Vtis4NdPaWyUqcejb7 RtA7bXBAQxsCmM83UCqwI/z3YGE1L69TDON1QuVoZ157kj45iypGM4D X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Paul Cercueil Change its name to iio_dma_buffer_usage(), as this function can be used both for the .data_available and the .space_available callbacks. Signed-off-by: Paul Cercueil --- drivers/iio/buffer/industrialio-buffer-dma.c | 11 ++++++----- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 2 +- include/linux/iio/buffer-dma.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 5610ba67925e..404f9867bdc5 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -547,13 +547,14 @@ int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, EXPORT_SYMBOL_GPL(iio_dma_buffer_read); /** - * iio_dma_buffer_data_available() - DMA buffer data_available callback + * iio_dma_buffer_usage() - DMA buffer data_available and + * space_available callback * @buf: Buffer to check for data availability * - * Should be used as the data_available callback for iio_buffer_access_ops - * struct for DMA buffers. + * Should be used as the data_available and space_available callbacks for + * iio_buffer_access_ops struct for DMA buffers. */ -size_t iio_dma_buffer_data_available(struct iio_buffer *buf) +size_t iio_dma_buffer_usage(struct iio_buffer *buf) { struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buf); struct iio_dma_buffer_block *block; @@ -586,7 +587,7 @@ size_t iio_dma_buffer_data_available(struct iio_buffer *buf) return data_available; } -EXPORT_SYMBOL_GPL(iio_dma_buffer_data_available); +EXPORT_SYMBOL_GPL(iio_dma_buffer_usage); /** * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index a18c1da292af..ccf6e0b19019 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -117,7 +117,7 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = { .request_update = iio_dma_buffer_request_update, .enable = iio_dma_buffer_enable, .disable = iio_dma_buffer_disable, - .data_available = iio_dma_buffer_data_available, + .data_available = iio_dma_buffer_usage, .release = iio_dmaengine_buffer_release, .modes = INDIO_BUFFER_HARDWARE, diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 18d3702fa95d..52a838ec0e57 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -132,7 +132,7 @@ int iio_dma_buffer_disable(struct iio_buffer *buffer, struct iio_dev *indio_dev); int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, char __user *user_buffer); -size_t iio_dma_buffer_data_available(struct iio_buffer *buffer); +size_t iio_dma_buffer_usage(struct iio_buffer *buffer); int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd); int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length); int iio_dma_buffer_request_update(struct iio_buffer *buffer); From patchwork Fri Feb 16 14:10:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560075 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 EF7CB12E1E8 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092690; cv=none; b=TkSM7ntC2ptyjzvpvvpM8rV0lpS/DEJkkQ6HBx3RBu+U90o8/2Xkto7Q9/kB+EgzYn+1FEjmSEf8eyUKT7cg2r9CRgY1mGmBGBHa71BkQCCKZmuFSbnG6tpqe6/f5kRQCvAr0abgRivHJmTd1OtH8oobdt3jqNkXZR3kmXyShIM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092690; c=relaxed/simple; bh=K1bI3qSBsID6idTEBGaHrKCumxe2K3HYxfybRHk0M40=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Dbfde9L0rWJLBKma9/lxez19WV5gAJ/BxBfnRjStCKti32Q4iUG/87mkdinfExulluOsszfmR8YfIAtv5dh+OCa3bd98NIVs1Bi3PofvLGbqREgAC8KKeqpmAaGkzkvw4YnQk7+xT+XLKZkK7wgBM3aRIA0xQ1xh5V2Jnz0d2eE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kkX3of4i; 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="kkX3of4i" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5D9A7C43399; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=K1bI3qSBsID6idTEBGaHrKCumxe2K3HYxfybRHk0M40=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=kkX3of4i9NyPcU48ivH5plMUxwLJV7FP3BupktQLCSV2JRED3kC1dcwhUbAibkYRo xbtT+pmjjUqqqpPb0M7PMWTiygy0dYLqyXhbDi2+OcdQ4OXoPb2ZSuKLNLIqhJ8rvc VGkATHUXcvdUVqwDf1QCV8KNRwMyQR2uW7gqNm1dyYrgiCrgBKGQxhqg5CEWgpPtDB jo5Q743uxJttlMNtGRXRxmqvcK3Z7PwHroGyxsxsGc3y4wsM7YalNX+lQZ2VRL0C/v 3IrLuweZ9+C/ysZZ43aZnCfcCQOvWU28ITjKn4J4W+ySNMqYuAv/BmfxG/9tLG6Jg7 ppeu6RfeET3cg== 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 3D088C48BF6; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:52 +0100 Subject: [PATCH RFC 3/8] iio: buffer-dma: Enable buffer write support Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-3-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich , Paul Cercueil , Alexandru Ardelean X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=6566; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=L8Ql02GphZ76a78MQMNepoZSe0z1Oo9UelhjeRQ/JC8=; b=wVKa+4l8K+gInZdPI43AQx55LuIW2RzzX2POck+SSNsQFlonW2fbmd1laR6qhF7IuxLzdWfij k/EUH0EKPiFAkHfaWoOp0OnRnYadULH7RQuNz/mH/kcF8hn5Gi8WXBf X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Paul Cercueil Adding write support to the buffer-dma code is easy - the write() function basically needs to do the exact same thing as the read() function: dequeue a block, read or write the data, enqueue the block when entirely processed. Therefore, the iio_buffer_dma_read() and the new iio_buffer_dma_write() now both call a function iio_buffer_dma_io(), which will perform this task. Note that we preemptively reset block->bytes_used to the buffer's size in iio_dma_buffer_request_update(), as in the future the iio_dma_buffer_enqueue() function won't reset it. Signed-off-by: Paul Cercueil Reviewed-by: Alexandru Ardelean --- drivers/iio/buffer/industrialio-buffer-dma.c | 89 +++++++++++++++++++++++----- include/linux/iio/buffer-dma.h | 2 + 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 404f9867bdc5..29cc3083cb7e 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -195,6 +195,18 @@ static void _iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) block->state = IIO_BLOCK_STATE_DONE; } +static void iio_dma_buffer_queue_wake(struct iio_dma_buffer_queue *queue) +{ + __poll_t flags; + + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) + flags = EPOLLIN | EPOLLRDNORM; + else + flags = EPOLLOUT | EPOLLWRNORM; + + wake_up_interruptible_poll(&queue->buffer.pollq, flags); +} + /** * iio_dma_buffer_block_done() - Indicate that a block has been completed * @block: The completed block @@ -212,7 +224,7 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) spin_unlock_irqrestore(&queue->list_lock, flags); iio_buffer_block_put_atomic(block); - wake_up_interruptible_poll(&queue->buffer.pollq, EPOLLIN | EPOLLRDNORM); + iio_dma_buffer_queue_wake(queue); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done); @@ -241,7 +253,7 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue, } spin_unlock_irqrestore(&queue->list_lock, flags); - wake_up_interruptible_poll(&queue->buffer.pollq, EPOLLIN | EPOLLRDNORM); + iio_dma_buffer_queue_wake(queue); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort); @@ -335,8 +347,24 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) queue->fileio.blocks[i] = block; } - block->state = IIO_BLOCK_STATE_QUEUED; - list_add_tail(&block->head, &queue->incoming); + /* + * block->bytes_used may have been modified previously, e.g. by + * iio_dma_buffer_block_list_abort(). Reset it here to the + * block's so that iio_dma_buffer_io() will work. + */ + block->bytes_used = block->size; + + /* + * If it's an input buffer, mark the block as queued, and + * iio_dma_buffer_enable() will submit it. Otherwise mark it as + * done, which means it's ready to be dequeued. + */ + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) { + block->state = IIO_BLOCK_STATE_QUEUED; + list_add_tail(&block->head, &queue->incoming); + } else { + block->state = IIO_BLOCK_STATE_DONE; + } } out_unlock: @@ -488,20 +516,12 @@ static struct iio_dma_buffer_block *iio_dma_buffer_dequeue( return block; } -/** - * iio_dma_buffer_read() - DMA buffer read callback - * @buffer: Buffer to read form - * @n: Number of bytes to read - * @user_buffer: Userspace buffer to copy the data to - * - * Should be used as the read callback for iio_buffer_access_ops - * struct for DMA buffers. - */ -int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, - char __user *user_buffer) +static int iio_dma_buffer_io(struct iio_buffer *buffer, size_t n, + char __user *user_buffer, bool is_from_user) { struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); struct iio_dma_buffer_block *block; + void *addr; int ret; if (n < buffer->bytes_per_datum) @@ -524,8 +544,13 @@ int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, n = rounddown(n, buffer->bytes_per_datum); if (n > block->bytes_used - queue->fileio.pos) n = block->bytes_used - queue->fileio.pos; + addr = block->vaddr + queue->fileio.pos; - if (copy_to_user(user_buffer, block->vaddr + queue->fileio.pos, n)) { + if (is_from_user) + ret = copy_from_user(addr, user_buffer, n); + else + ret = copy_to_user(user_buffer, addr, n); + if (ret) { ret = -EFAULT; goto out_unlock; } @@ -544,8 +569,40 @@ int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, return ret; } + +/** + * iio_dma_buffer_read() - DMA buffer read callback + * @buffer: Buffer to read form + * @n: Number of bytes to read + * @user_buffer: Userspace buffer to copy the data to + * + * Should be used as the read callback for iio_buffer_access_ops + * struct for DMA buffers. + */ +int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, + char __user *user_buffer) +{ + return iio_dma_buffer_io(buffer, n, user_buffer, false); +} EXPORT_SYMBOL_GPL(iio_dma_buffer_read); +/** + * iio_dma_buffer_write() - DMA buffer write callback + * @buffer: Buffer to read form + * @n: Number of bytes to read + * @user_buffer: Userspace buffer to copy the data from + * + * Should be used as the write callback for iio_buffer_access_ops + * struct for DMA buffers. + */ +int iio_dma_buffer_write(struct iio_buffer *buffer, size_t n, + const char __user *user_buffer) +{ + return iio_dma_buffer_io(buffer, n, + (__force __user char *)user_buffer, true); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_write); + /** * iio_dma_buffer_usage() - DMA buffer data_available and * space_available callback diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 52a838ec0e57..6e27e47077d5 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -132,6 +132,8 @@ int iio_dma_buffer_disable(struct iio_buffer *buffer, struct iio_dev *indio_dev); int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, char __user *user_buffer); +int iio_dma_buffer_write(struct iio_buffer *buffer, size_t n, + const char __user *user_buffer); size_t iio_dma_buffer_usage(struct iio_buffer *buffer); int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd); int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length); From patchwork Fri Feb 16 14:10:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560073 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 C01AF12E1F2 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092689; cv=none; b=TTczesKUH+ok8svthfCwpRhESTEVEOQa2IAi9ZHLLQhQoBJ5zvIzBCDtokZOFqNq+MdwiJk8BpmLaZu1A9o3xDX+cmc/uQ107Dv3Wd4LCISSTFDYKgQWhWnplAQx85xtB50sfWBgpyVLGanfpPLGVg8NHu2icotA1CFuidNUTbg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092689; c=relaxed/simple; bh=zrbBh0Aw33I9O/+ftBMnbcEQC7hb4RDV/E6G2FU8P84=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BjShtkrKewuAmeV0FtfrviwsdNLNdZ3FWR0RYTLPU1BFSwNlS024KipwVSaiGtnIQs5Ezzl58OHtsL6b5ZSFAYckm3E7mTmvIqUhSo18FjmBzwMr6kENv07oARsipYTSdDvMwdummxDLMes4CeMQVRbbPanHsMyTVwJbbAJxyac= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=a+00sXCO; 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="a+00sXCO" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5FA0FC433A6; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=zrbBh0Aw33I9O/+ftBMnbcEQC7hb4RDV/E6G2FU8P84=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=a+00sXCOA6i625ZFbf4YZEenMT1Icjg3t5cAuOGkxkEI2zQgs6fKbuft9h/iIXUz2 70BizYD+Hs+ycoc692OGyx6aLOfUsRDuchOYE5nDNGHd5S3c3FqegaagsDpbKNv7EC AptaAtCIRV3spJe0EJSmQ6j0CQa5hezeJP67mnG69CCk4gkp94M5mY5zPxY9vDrPJ/ 195GI64wccu6CO5FmW7BYWrXNollv/tfXcq3ZJD7tGqd567GWnZLOwybDKYODoOP2r Xsnhifdh4tea2oHHpMkWt7M7vlkeWnz+txOGC68wNDJA1h7zA+/xmwzvt9D+4um9N+ CIxksMjg4NPqA== 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 4A21AC48BF5; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:53 +0100 Subject: [PATCH RFC 4/8] iio: buffer-dmaengine: Support specifying buffer direction Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-4-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich , Paul Cercueil , Alexandru Ardelean X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=3316; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=/2paaSaUSUtnmD8m+C6v5CZcE58NPbZ+OtcbaI8FBrI=; b=agjbEFXThMyCk/MtP+kElOxF8eX9Wykk+QoKm8Lpzk25IIYZy7eV4VCt5/pSUlEWCzphYLhDI 0O2vg8fYhn5AgFQWj0a4GjemUAMFGeSg4qVEDhsJ7HQaYNc089ie6Lc X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Paul Cercueil Update the devm_iio_dmaengine_buffer_setup() function to support specifying the buffer direction. Update the iio_dmaengine_buffer_submit() function to handle input buffers as well as output buffers. Signed-off-by: Paul Cercueil Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 24 +++++++++++++++++----- include/linux/iio/buffer-dmaengine.h | 5 ++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index ccf6e0b19019..d9d72f7cba60 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -64,14 +64,25 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, struct dmaengine_buffer *dmaengine_buffer = iio_buffer_to_dmaengine_buffer(&queue->buffer); struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dma_dir; + size_t max_size; dma_cookie_t cookie; - block->bytes_used = min(block->size, dmaengine_buffer->max_size); - block->bytes_used = round_down(block->bytes_used, - dmaengine_buffer->align); + max_size = min(block->size, dmaengine_buffer->max_size); + max_size = round_down(max_size, dmaengine_buffer->align); + + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) { + block->bytes_used = max_size; + dma_dir = DMA_DEV_TO_MEM; + } else { + dma_dir = DMA_MEM_TO_DEV; + } + + if (!block->bytes_used || block->bytes_used > max_size) + return -EINVAL; desc = dmaengine_prep_slave_single(dmaengine_buffer->chan, - block->phys_addr, block->bytes_used, DMA_DEV_TO_MEM, + block->phys_addr, block->bytes_used, dma_dir, DMA_PREP_INTERRUPT); if (!desc) return -ENOMEM; @@ -277,7 +288,8 @@ static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, */ int devm_iio_dmaengine_buffer_setup(struct device *dev, struct iio_dev *indio_dev, - const char *channel) + const char *channel, + enum iio_buffer_direction dir) { struct iio_buffer *buffer; @@ -287,6 +299,8 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, indio_dev->modes |= INDIO_BUFFER_HARDWARE; + buffer->direction = dir; + return iio_device_attach_buffer(indio_dev, buffer); } EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index cbb8ba957fad..ea9a539bfa20 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -7,6 +7,8 @@ #ifndef __IIO_DMAENGINE_H__ #define __IIO_DMAENGINE_H__ +#include + struct iio_dev; struct device; @@ -15,6 +17,7 @@ struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, void iio_dmaengine_buffer_free(struct iio_buffer *buffer); int devm_iio_dmaengine_buffer_setup(struct device *dev, struct iio_dev *indio_dev, - const char *channel); + const char *channel, + enum iio_buffer_direction dir); #endif From patchwork Fri Feb 16 14:10:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560074 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 C01EA12E1F4 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092689; cv=none; b=Vohb7LD3rSwr9WPh9njVY2sEkGvnq7DbYUPmPQM4WvQ3IcORc9qZ35LR7p34FdLfqRWwLllWm+VA5SMX4tFaTiMpjxSxevmyvurQYH6X+6n0COb7w+N8M8zWv3TaaKETzoCDAg2PFeNAAuZab6f1yOhYiBnfl1OE/s1qhJNzPuE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092689; c=relaxed/simple; bh=EG20HCsns1ASyKJ4WWYbYFU9zLiRImH2DNuvQxu5Xa4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Vwp08+EkdzA68Fxclhgv4Y4kwwbor7zPpP5zC6TPpX3Z3NnU3F37+0wOJUX+k1QdxKvBKzoMaCqhqEQEIHw3nRSwe7rmi/EzjtMIA52hTDVkwu0foDeSbl85n98PSW/JAYsz1rycJHxPxnEW/LC625TMpUNywk40BV6UM6RC40A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=otV1+gJB; 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="otV1+gJB" Received: by smtp.kernel.org (Postfix) with ESMTPS id 69A88C43601; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=EG20HCsns1ASyKJ4WWYbYFU9zLiRImH2DNuvQxu5Xa4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=otV1+gJB552r5G5/TrOy3nz2VOZS31v0Zd3kNXteHeXuqu+ceR+M86xmhXO1zPDyg Ezx3bMAXthBtfTTENBGprlbr339eh60KorTMSnec5bxoeObWK5oYrCyqNP/dWpdc30 XWAdaFuOCy77fkLPBq/bDO5eLopw6ozK5XQ6FjxdJjodULFfjBOI8fSHayI+N1o7nB Y2DWQtJU7M962YcgP039DWci//WgyjywAr11OT7ivq6iCrQUkYb3xbzGG5iITUSr76 fQkzI4jerqifh6s2Y0hpbPUM1CYf1iVnwWfg5pUvzCw4bfbI7d6bH59xnVXqNUhEY+ TwG2xCZNhDqtw== 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 53926C48BF8; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:54 +0100 Subject: [PATCH RFC 5/8] iio: buffer-dmaengine: Enable write support Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-5-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich , Paul Cercueil , Alexandru Ardelean X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=1305; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=EuXm3wJiZVoFIehccCqYYu9vYz4WznwXf643rUy0LM4=; b=7cufpt+bWCqi4PSi62gexvonacFYiF9ykFxSuSjQjzJDaOXTm1hPQeY/R8fiT7CsTPS/hloDe BnTGHCE9fICD6Hqf8FtYAVwXQTt7oZv2z8JjWWqUKZzpF+tumPzVYhY X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Paul Cercueil Use the iio_dma_buffer_write() and iio_dma_buffer_space_available() functions provided by the buffer-dma core, to enable write support in the buffer-dmaengine code. Signed-off-by: Paul Cercueil Reviewed-by: Alexandru Ardelean --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index d9d72f7cba60..e151af7e8907 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -123,12 +123,14 @@ static void iio_dmaengine_buffer_release(struct iio_buffer *buf) static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = { .read = iio_dma_buffer_read, + .write = iio_dma_buffer_write, .set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum, .set_length = iio_dma_buffer_set_length, .request_update = iio_dma_buffer_request_update, .enable = iio_dma_buffer_enable, .disable = iio_dma_buffer_disable, .data_available = iio_dma_buffer_usage, + .space_available = iio_dma_buffer_usage, .release = iio_dmaengine_buffer_release, .modes = INDIO_BUFFER_HARDWARE, From patchwork Fri Feb 16 14:10:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560076 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 EF82312EBC3 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092690; cv=none; b=ZiKv0QvaBRS51zZxJguCZjQUhFDfaB/c6NmFsrCGA43futFiG/p3uWl5unhsHFSUThH9yYjLr6P0i/ES7sYPi6re2jlVHqBPbElLM71dmMEskMjOHyOkg/he3LSrImOcyN4SCWzjBUopuQ3G27IXoB8FAREMBCPJFhgqAqlc5cc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092690; c=relaxed/simple; bh=zbYdxYyLR1xJLzpkg8i7cPdJipb8RgdsnXGGrxP71ys=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ovSiv9/O1qw03Gnpw/e9DQCrlG2G8mDsxOXgHg9Q3PeePSGnC+pT7vQX/YWrCUlL8q5SoOQWpPe74iUhm64v2L3LGAag4acj6pOox30KCJq5N5JNl8cGgSJon1P/Ns6XVwDRsNU+HL4eyVKgCXASK1vt3sWuOJUyXLKkytqIvZY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qtdhKqb5; 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="qtdhKqb5" Received: by smtp.kernel.org (Postfix) with ESMTPS id 769CFC43330; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=zbYdxYyLR1xJLzpkg8i7cPdJipb8RgdsnXGGrxP71ys=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=qtdhKqb5Fy2YWKTGNn6khEu51azIqs7VD/y3QXxJ4sVYf3tKIBYiNbY9TNo1Dusql mJNx5GSaExONln1oCTZ1cPKS7+UL+AaW2ROcnYEblhJrnZ99SvXVHc0Eq/uYcVZXrh E1F2FndveXs3o5yJfcfMuvdy9yk4DG+D8Nowv+3mnF9yDDCf3SDqKrwL/BYhJPpfw+ 6HRFU0hGxUpRj0/xIxhA3b25eq3xe5LlBPgZsAj0VjsdUlLltHL/isxrLPuQ3MyJa/ VMBbUZCWKcZv+2rm/ZKnWogojxdCl+/a2cljIObCfYmTi0UNcjb6FzgwRjFM6TGFrU ML6OnkSEdossg== 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 60A66C48260; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:55 +0100 Subject: [PATCH RFC 6/8] iio: backend: add new backend ops Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-6-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=8015; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=rN0QCjqlMVi6zhSqFla2kqXViqpt4/ebJYdlaVhTU4w=; b=tWjrufsIIy7RSRrg6PW8H8zFeFPTk1jCjL2uOcJrCQVney0BQhF3jSZch1Rk+J6TjZXXxvEUa JR74dN65SzwAYXrXmQeQz6bdXeBGRbjnz/Q/1/cH1LGxMOKyRj06dJJ X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Nuno Sa The following new ops are being added: - iio_backend_data_source_set() - iio_backend_read_phase() - iio_backend_write_phase() - iio_backend_read_scale() - iio_backend_write_scale() - iio_backend_read_frequency() - iio_backend_write_frequency() The new iio_backend_data_source_set() allows to select the data source on a backend. It can for example be used when enabling/disabling a buffer to mux between different data sources. The rest of the APIs mostly resemble (apart from read/write frequency which have a couple of new arguments) the typical read/write raw functions (but fine grained for a specific attribute). Signed-off-by: Nuno Sa --- drivers/iio/industrialio-backend.c | 65 ++++++++++++++++++++++++++++++++++++++ include/linux/iio/backend.h | 53 ++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 2fea2bbbe47f..bf26c41872ca 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -43,6 +43,7 @@ #include #include +#include struct iio_backend { struct list_head entry; @@ -186,6 +187,16 @@ int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, } EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); +int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data) +{ + if (data >= IIO_BACKEND_DATA_SOURCE_MAX) + return -EINVAL; + + return iio_backend_op_call(back, data_source_set, chan, data); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, IIO_BACKEND); + static void iio_backend_free_buffer(void *arg) { struct iio_backend_buffer_pair *pair = arg; @@ -231,6 +242,60 @@ int devm_iio_backend_request_buffer(struct device *dev, } EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); +int iio_backend_read_phase(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx) +{ + return iio_backend_op_call(back, read_phase, chan, val, val2, tone_idx); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_read_phase, IIO_BACKEND); + +int iio_backend_write_phase(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx) +{ + return iio_backend_op_call(back, write_phase, chan, val, val2, + tone_idx); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_write_phase, IIO_BACKEND); + +int iio_backend_read_scale(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx) +{ + return iio_backend_op_call(back, read_scale, chan, val, val2, tone_idx); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_read_scale, IIO_BACKEND); + +int iio_backend_write_scale(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx) +{ + return iio_backend_op_call(back, write_scale, chan, val, val2, + tone_idx); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_write_scale, IIO_BACKEND); + +int iio_backend_read_frequency(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx, + unsigned long long sample_freq) +{ + return iio_backend_op_call(back, read_frequency, chan, val, val2, + tone_idx, sample_freq); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_read_frequency, IIO_BACKEND); + +int iio_backend_write_frequency(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx, + unsigned long long sample_freq) +{ + return iio_backend_op_call(back, write_frequency, chan, val, val2, + tone_idx, sample_freq); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_write_frequency, IIO_BACKEND); + static void iio_backend_release(void *arg) { struct iio_backend *back = arg; diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index a6d79381866e..c5bcbe89cb64 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -4,6 +4,7 @@ #include +struct iio_chan_spec; struct fwnode_handle; struct iio_backend; struct device; @@ -15,6 +16,12 @@ enum iio_backend_data_type { IIO_BACKEND_DATA_TYPE_MAX }; +enum iio_backend_data_source { + IIO_BACKEND_INTERNAL_CW, + IIO_BACKEND_EXTERNAL, + IIO_BACKEND_DATA_SOURCE_MAX +}; + /** * struct iio_backend_data_fmt - Backend data format * @type: Data type. @@ -45,10 +52,33 @@ struct iio_backend_ops { int (*chan_disable)(struct iio_backend *back, unsigned int chan); int (*data_format_set)(struct iio_backend *back, unsigned int chan, const struct iio_backend_data_fmt *data); + int (*data_source_set)(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data); + struct iio_buffer *(*request_buffer)(struct iio_backend *back, struct iio_dev *indio_dev); void (*free_buffer)(struct iio_backend *back, struct iio_buffer *buffer); + int (*read_phase)(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, int *val2, + unsigned int tone_idx); + int (*write_phase)(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, int val2, + unsigned int tone_idx); + int (*read_scale)(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, int *val2, + unsigned int tone_idx); + int (*write_scale)(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, int val2, + unsigned int tone_idx); + int (*read_frequency)(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx, + unsigned long long sample_freq); + int (*write_frequency)(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx, + unsigned long long sample_freq); }; int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan); @@ -56,10 +86,31 @@ int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan); int devm_iio_backend_enable(struct device *dev, struct iio_backend *back); int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, const struct iio_backend_data_fmt *data); +int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data); int devm_iio_backend_request_buffer(struct device *dev, struct iio_backend *back, struct iio_dev *indio_dev); - +int iio_backend_read_phase(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx); +int iio_backend_write_phase(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx); +int iio_backend_read_scale(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx); +int iio_backend_write_scale(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx); +int iio_backend_read_frequency(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx, + unsigned long long sample_freq); +int iio_backend_write_frequency(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx, + unsigned long long sample_freq); void *iio_backend_get_priv(const struct iio_backend *conv); struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name); struct iio_backend * From patchwork Fri Feb 16 14:10:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560078 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 F1DB312EBC4 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092690; cv=none; b=gbYxPFzs69s/rj19YpoFVlQoBG+wvtkRqgxUN41YBRJP4smLCSu0KeOU9m65nA9P8Als9V92a/sL+Mz/UFTmAh+z+YFyZl+b+RMbZvnVU4of14xsbzGzwD2+ucMFumt4xMeOnn+VyNfYhpFaI3LxdwowbgWDIOJVA/YzToSCTek= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092690; c=relaxed/simple; bh=vAmWd+tUeWZ+abFMMHSQn/BJPKH9dI95nxkPn1ibv8s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lluEoFPPSqgSxKvyoRvlMnfi0B7aZWvviUZNWiX6dGrYzDO0Rf1RDQh4brW3E/qHZDZXOAKT2oURUau29iPG5eJz5y+NMRJPIc8TAuxsWUbmqUrS7hnRmcbXd2dARNbWX0qQvbxVsEsyg8GkdmVMP1kLMXnub67kT75TD5h6/wc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cK9/uFyG; 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="cK9/uFyG" Received: by smtp.kernel.org (Postfix) with ESMTPS id 8251FC4166A; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=vAmWd+tUeWZ+abFMMHSQn/BJPKH9dI95nxkPn1ibv8s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=cK9/uFyGogiQunVKtEgQIv6pFKq11A2g+/7pXimBeYuYmBwb7ptZ19pqiw+xidjGW PgPlmq7cfwCa18YjsepwIKnlZqe/xZRVqsqbkalAgY9r4/X0qGoUH03LXOH1ArVN2A HaYC9bBZHcm8Mdwq/97YQyNXXsKbICtopgMU1OsZELqWYd5/jHdzmqfY+stil1sa/x bKB4YKrmPv78J0bObgOhyNtksFCiUwspt5ydunk4GflmfnB7CI240k4TBief60VhVf m6isC5fmQzXZa04rdrpwWTYXDoCCQLNsCNEb2VEzg2BhQaLsIaXMjA+kc1nZ6BM0Xa p/sssOrXPofOQ== 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 6C6D7C48BEF; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:56 +0100 Subject: [PATCH RFC 7/8] iio: dac: add support for the AD97339A RF DAC Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-7-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=16425; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=JvJEEC42EH4Jf6P2LRlyeWRmTv3p1qbMMrzLpMLfAY0=; b=kG4+co4yDOxLFyW6Ihq7htzqnit4H23CfqxQtRaqCIfrKYug9g765u46AoClaPCvkevKMpYGM cqQ4yoh1eIUBV7JSC94h9lRxOYb9mkr1uxjoN6NZyge9+0JoK1xz/oM X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Nuno Sa The AD9739A is a 14-bit, 2.5 GSPS high performance RF DAC that is capable of synthesizing wideband signals from dc up to 3 GHz. On-chip controllers are used to manage external and internal clock domain variations over temperature to ensure reliable data transfer from the host to the DAC core. Signed-off-by: Nuno Sa --- drivers/iio/dac/Kconfig | 16 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad9739a.c | 503 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 520 insertions(+) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 34eb40bb9529..98e80e73fab5 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -131,6 +131,22 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config AD9739A + tristate "Analog Devices AD9739A RF DAC spi driver" + depends on SPI + select REGMAP_SPI + select IIO_BACKEND + help + Say yes here to build support for Analog Devices AD9739A Digital-to + Analog Converter. + + The driver requires the assistance of the AXI DAC IP core to operate, + since SPI is used for configuration only, while data has to be + streamed into memory via DMA. + + To compile this driver as a module, choose M here: the module will be + called ad9739a. + config LTC2688 tristate "Analog Devices LTC2688 DAC spi driver" depends on SPI diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 55bf89739d14..7e39e0c218ca 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o obj-$(CONFIG_AD7293) += ad7293.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o +obj-$(CONFIG_AD9739A) += ad9739a.o obj-$(CONFIG_CIO_DAC) += cio-dac.o obj-$(CONFIG_DPOT_DAC) += dpot-dac.o obj-$(CONFIG_DS4424) += ds4424.o diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c new file mode 100644 index 000000000000..e4ade13aaf00 --- /dev/null +++ b/drivers/iio/dac/ad9739a.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD9739a SPI DAC driver + * + * Copyright 2015-2024 Analog Devices Inc. + */ + +#include "linux/delay.h" +#include "linux/dev_printk.h" +#include "linux/gpio/consumer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define AD9739A_REG_MODE 0 +#define AD9739A_RESET_MASK BIT(5) +#define AD9739A_REG_LVDS_REC_CNT1 0x10 +#define AD9739A_RCVR_LOOP_EN_MASK GENMASK(1, 0) +#define AD9739A_REG_LVDS_REC_CNT4 0x13 +#define AD9739A_FINE_DEL_SKW_MASK GENMASK(3, 0) +#define AD9739A_REG_LVDS_REC_STAT9 0x21 +#define AD9739A_RCVR_TRACK_AND_LOCK (BIT(3) | BIT(0)) +#define AD9739A_REG_CROSS_CNT1 0x22 +#define AD9739A_REG_CROSS_CNT2 0x23 +#define AD9739A_REG_PHS_DET 0x24 +#define AD9739A_REG_MU_DUTY 0x25 +#define AD9739A_REG_MU_CNT1 0x26 +#define AD9739A_MU_EN_MASK BIT(0) +#define AD9739A_REG_MU_CNT2 0x27 +#define AD9739A_REG_MU_CNT3 0x28 +#define AD9739A_REG_MU_CNT4 0x29 +#define AD9739A_MU_CNT4_DEFAULT 0xcb +#define AD9739A_REG_MU_STAT1 0x2A +#define AD9739A_MU_LOCK_MASK BIT(0) +#define AD9739A_REG_ANA_CNT_1 0x32 +#define AD9739A_REG_ID 0x35 + +#define AD9739A_ID 0x24 +#define AD9739A_REG_IS_RESERVED(reg) \ + ((reg) == 0x5 || (reg) == 0x9 || (reg) == 0x0E || (reg) == 0x0D || \ + (reg) == 0x2B || (reg) == 0x2C || (reg) == 0x34) + +#define AD9739A_MIN_DAC_CLK (1600 * MEGA) +#define AD9739A_MAX_DAC_CLK (2500 * MEGA) +#define AD9739A_DAC_CLK_RANGE (AD9739A_MAX_DAC_CLK - AD9739A_MIN_DAC_CLK + 1) +/* as recommended by the datasheet */ +#define AD9739A_LOCK_N_TRIES 3 + +struct ad9739a_state { + struct iio_backend *back; + struct regmap *regmap; + unsigned long sample_rate; +}; + +static int ad9739a_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->sample_rate; + *val2 = 0; + return IIO_VAL_INT_64; + default: + return -EINVAL; + } +} + +enum { + AD9739A_TONE_1, + AD9739A_TONE_2, +}; + +static ssize_t ad9739a_read_ext_info(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf, + int (*backend_op)(struct iio_backend *back, + const struct iio_chan_spec *chan, + int *val, int *val2, + unsigned int tone_idx)) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + int ret, vals[2], tone = 0; + + if (private == AD9739A_TONE_2) + tone++; + + ret = backend_op(st->back, chan, &vals[0], &vals[1], tone); + if (ret < 0) + return ret; + + return iio_format_value(buf, ret, ARRAY_SIZE(vals), vals); +} + +static ssize_t ad9739a_write_ext_info(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len, + int (*backend_op)(struct iio_backend *back, + const struct iio_chan_spec *chan, + int val, int val2, + unsigned int tone_idx)) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + int ret, integer, frac, tone = 0; + + /* assumed IIO_VAL_INT_PLUS_MICRO */ + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); + if (ret) + return ret; + + if (private == AD9739A_TONE_2) + tone++; + + ret = backend_op(st->back, chan, integer, frac, tone); + if (ret) + return ret; + + return len; +} + +static ssize_t ad9739a_frequency_get(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + int ret, vals[2], tone = 0; + + if (private == AD9739A_TONE_2) + tone++; + + ret = iio_backend_read_frequency(st->back, chan, &vals[0], &vals[1], + tone, st->sample_rate); + if (ret < 0) + return ret; + + return iio_format_value(buf, ret, ARRAY_SIZE(vals), vals); +} + +static ssize_t ad9739a_frequency_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + int ret, integer, frac, tone = 0; + + /* assumed IIO_VAL_INT_PLUS_MICRO */ + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); + if (ret) + return ret; + + if (private == AD9739A_TONE_2) + tone++; + + ret = iio_backend_write_frequency(st->back, chan, integer, frac, tone, + st->sample_rate); + if (ret) + return ret; + + return len; +} + +static ssize_t ad9739a_scale_get(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + return ad9739a_read_ext_info(indio_dev, private, chan, buf, + iio_backend_read_scale); +} + +static ssize_t ad9739a_scale_set(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + return ad9739a_write_ext_info(indio_dev, private, chan, buf, len, + iio_backend_write_scale); +} + +static ssize_t ad9739a_phase_get(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + return ad9739a_read_ext_info(indio_dev, private, chan, buf, + iio_backend_read_phase); +} + +static ssize_t ad9739a_phase_set(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + return ad9739a_write_ext_info(indio_dev, private, chan, buf, len, + iio_backend_write_phase); +} + +static int ad9739a_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + return iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL); +} + +static int ad9739a_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + return iio_backend_data_source_set(st->back, 0, + IIO_BACKEND_INTERNAL_CW); +} + +static bool ad9739a_reg_accessible(struct device *dev, unsigned int reg) +{ + if (AD9739A_REG_IS_RESERVED(reg)) + return false; + if (reg > AD9739A_REG_MU_STAT1 && reg < AD9739A_REG_ANA_CNT_1) + return false; + + return true; +} + +static int ad9739a_reset(struct device *dev, const struct ad9739a_state *st) +{ + struct gpio_desc *gpio; + int ret; + + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + if (gpio) { + /* minimum pulse width of 40ns */ + ndelay(40); + gpiod_set_value_cansleep(gpio, 0); + return 0; + } + + /* bring all registers to their default state */ + ret = regmap_set_bits(st->regmap, AD9739A_REG_MODE, AD9739A_RESET_MASK); + if (ret) + return ret; + + ndelay(40); + + return regmap_clear_bits(st->regmap, AD9739A_REG_MODE, + AD9739A_RESET_MASK); +} + +/* + * Recommended values (as per datasheet) for the dac clk common mode voltage + * and Mu controller. Look at table 29. + */ +static const struct reg_sequence ad9739a_clk_mu_ctrl[] = { + /* DAC clk common mode voltage */ + {AD9739A_REG_CROSS_CNT1, 0x0f}, + {AD9739A_REG_CROSS_CNT2, 0x0f}, + /* Mu controller configuration */ + {AD9739A_REG_PHS_DET, 0x30}, + {AD9739A_REG_MU_DUTY, 0x80}, + {AD9739A_REG_MU_CNT2, 0x44}, + {AD9739A_REG_MU_CNT3, 0x6c}, +}; + +static int ad9739a_init(struct device *dev, const struct ad9739a_state *st) +{ + unsigned int i = 0, lock; + int ret; + + ret = regmap_multi_reg_write(st->regmap, ad9739a_clk_mu_ctrl, + ARRAY_SIZE(ad9739a_clk_mu_ctrl)); + if (ret) + return ret; + + /* + * Try to get the MU lock. Repeat the below steps AD9739A_LOCK_N_TRIES + * (as specified by the datasheet) until we get the lock. + */ + do { + ret = regmap_write(st->regmap, AD9739A_REG_MU_CNT4, + AD9739A_MU_CNT4_DEFAULT); + if (ret) + return ret; + + /* Enable the Mu controller search and track mode. */ + ret = regmap_set_bits(st->regmap, AD9739A_REG_MU_CNT1, + AD9739A_MU_EN_MASK); + if (ret) + return ret; + + /* Ensure the DLL loop is locked */ + ret = regmap_read_poll_timeout(st->regmap, AD9739A_REG_MU_STAT1, + lock, lock & AD9739A_MU_LOCK_MASK, + 0, 1000); + } while (ret && ++i < AD9739A_LOCK_N_TRIES); + + if (i == AD9739A_LOCK_N_TRIES) + return dev_err_probe(dev, ret, "Mu lock timeout\n"); + + /* Receiver tracking an lock. Same deal as the Mu controller */ + i = 0; + do { + ret = regmap_update_bits(st->regmap, AD9739A_REG_LVDS_REC_CNT4, + AD9739A_FINE_DEL_SKW_MASK, + FIELD_PREP(AD9739A_FINE_DEL_SKW_MASK, 2)); + if (ret) + return ret; + + /* Disable the receiver and the loop. */ + ret = regmap_write(st->regmap, AD9739A_REG_LVDS_REC_CNT1, 0); + if (ret) + return ret; + + /* + * Re-enable the loop so it falls out of lock and begins the + * search/track routine again. + */ + ret = regmap_set_bits(st->regmap, AD9739A_REG_LVDS_REC_CNT1, + AD9739A_RCVR_LOOP_EN_MASK); + if (ret) + return ret; + + /* Ensure the DLL loop is locked */ + ret = regmap_read_poll_timeout(st->regmap, + AD9739A_REG_LVDS_REC_STAT9, lock, + lock == AD9739A_RCVR_TRACK_AND_LOCK, + 0, 1000); + } while (ret && ++i < AD9739A_LOCK_N_TRIES); + + if (i == AD9739A_LOCK_N_TRIES) + return dev_err_probe(dev, ret, "Receiver lock timeout\n"); + + return 0; +} + +static const struct iio_buffer_setup_ops ad9739a_buffer_setup_ops = { + .preenable = &ad9739a_buffer_preenable, + .postdisable = &ad9739a_buffer_postdisable, +}; + +static const struct iio_info ad9739a_info = { + .read_raw = ad9739a_read_raw, +}; + +static const struct regmap_config ad9739a_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .readable_reg = ad9739a_reg_accessible, + .writeable_reg = ad9739a_reg_accessible, + .max_register = AD9739A_REG_ID, +}; + +#define AD9739A_EXT_INFO(_name, _read, _write, _what) { \ + .name = (_name), \ + .private = (_what), \ + .read = (_read), \ + .write = (_write), \ + .shared = IIO_SEPARATE, \ +} + +static const struct iio_chan_spec_ext_info ad9739a_ext_info[] = { + AD9739A_EXT_INFO("frequency0", ad9739a_frequency_get, + ad9739a_frequency_set, AD9739A_TONE_1), + AD9739A_EXT_INFO("frequency1", ad9739a_frequency_get, + ad9739a_frequency_set, AD9739A_TONE_2), + AD9739A_EXT_INFO("scale0", ad9739a_scale_get, + ad9739a_scale_set, AD9739A_TONE_1), + AD9739A_EXT_INFO("scale1", ad9739a_scale_get, + ad9739a_scale_set, AD9739A_TONE_2), + AD9739A_EXT_INFO("phase0", ad9739a_phase_get, + ad9739a_phase_set, AD9739A_TONE_1), + AD9739A_EXT_INFO("phase1", ad9739a_phase_get, + ad9739a_phase_set, AD9739A_TONE_2), + {} +}; + +static const struct iio_chan_spec ad9739a_channel[] = { + { + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .output = 1, + .scan_index = -1, + .ext_info = ad9739a_ext_info, + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .output = 1, + .scan_type = { + .sign = 's', + .storagebits = 16, + .realbits = 16, + }, + } +}; + +static int ad9739a_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad9739a_state *st; + unsigned int id; + struct clk *clk; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "Could not get clkin\n"); + + st->sample_rate = clk_get_rate(clk); + if (!in_range(st->sample_rate, AD9739A_MIN_DAC_CLK, + AD9739A_DAC_CLK_RANGE)) + return dev_err_probe(dev, -EINVAL, + "Invalid dac clk range(%lu) [%lu %lu]\n", + st->sample_rate, AD9739A_MIN_DAC_CLK, + AD9739A_MAX_DAC_CLK); + + st->regmap = devm_regmap_init_spi(spi, &ad9739a_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + ret = regmap_read(st->regmap, AD9739A_REG_ID, &id); + if (ret) + return ret; + + if (id != AD9739A_ID) + return dev_err_probe(dev, -ENODEV, "Unrecognized CHIP_ID 0x%X", + id); + + ret = ad9739a_reset(dev, st); + if (ret) + return ret; + + ret = ad9739a_init(dev, st); + if (ret) + return ret; + + st->back = devm_iio_backend_get(dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + + ret = devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + + indio_dev->name = "ad9739a"; + indio_dev->info = &ad9739a_info; + indio_dev->channels = ad9739a_channel; + indio_dev->num_channels = ARRAY_SIZE(ad9739a_channel); + indio_dev->setup_ops = &ad9739a_buffer_setup_ops; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ad9739a_of_match[] = { + { .compatible = "adi,ad9739a" }, + {} +}; +MODULE_DEVICE_TABLE(of, ad9739a_of_match); + +static const struct spi_device_id ad9739a_id[] = { + {"ad9739a"}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad9739a_id); + +static struct spi_driver ad9739a_driver = { + .driver = { + .name = "ad9739a", + .of_match_table = ad9739a_of_match, + }, + .probe = ad9739a_probe, + .id_table = ad9739a_id, +}; +module_spi_driver(ad9739a_driver); + +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("Analog Devices AD9739 DAC"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_BACKEND); From patchwork Fri Feb 16 14:10:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuno Sa via B4 Relay X-Patchwork-Id: 13560077 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 EF78F12D761 for ; Fri, 16 Feb 2024 14:11:29 +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=1708092690; cv=none; b=KmlmItAP5dO1fIl83hgbm3Ry7J2V7MVAXf/AqlK0uQ0zFWZDmRV09kA99LHn5SNMHF+qBpPo91ut95eiWQ6E5u0dWET4OhOWMwFvRWvH6XZURmWxQDX9GzRoLeRtOjuss+U2XpAfJmKKM8ISp/IAmbpIKjT6vHRwsXW1c5t6J64= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708092690; c=relaxed/simple; bh=YhOGr+CA7o1hlK67baXP3eQNN3JnPRtmrYJF/tA7fEE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BE6AI1yBaRaUTZ36LWJO6qAkBd6/iTLDyIth1Ex/UWrdff15sSJNIORWFMZG/J8wdYc06ZqDJyVLKfW8ujEGSYv2WEbz3xZJJYTkGd5JNd11ThmK6hlyYch6IN6zBbzF/Fs+peuXAE0BZRPN9eo6qw0284Qp+nvNNS4rbf8ovNk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Er/DuA3/; 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="Er/DuA3/" Received: by smtp.kernel.org (Postfix) with ESMTPS id 8ADE7C43141; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708092689; bh=YhOGr+CA7o1hlK67baXP3eQNN3JnPRtmrYJF/tA7fEE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Er/DuA3/oAZ7vx7hMbhLPFj0AOTy9sSOaJcKKPtULDia5mw/q/fCgrSIjfQ8uwxUV l7fcK7Hsk2dj9w121i7Hd1jmzepk+xopEMDNTrZbjtyf+mhR/H/duJk55L6skYBi8g a9mNkC7m0wpRf5dgGPu+p7tCQaI7EZvRxo8lZxZI39kVh1BhBJFBYhoHEL5wijJrhc IG3WnYCzKdUIPiH4z/dfR2LztRhCYS3kgQNi3TwLwJ0ACO8KnuyUKqsj+0ck84j7du pJjckWBvJGQvkkkfl53Ry327hgodvn9cRCOxjLHdoabfUPLhWUa6HQQrAyJIbXIg9b GlFGg+W2ZJ0og== 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 78044C48BF5; Fri, 16 Feb 2024 14:11:29 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Fri, 16 Feb 2024 15:10:57 +0100 Subject: [PATCH RFC 8/8] iio: dac: adi-axi-dac: add support for AXI DAC IP core Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240216-iio-backend-axi-dds-v1-8-22aed9fb07a1@analog.com> References: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> In-Reply-To: <20240216-iio-backend-axi-dds-v1-0-22aed9fb07a1@analog.com> To: linux-iio@vger.kernel.org Cc: Jonathan Cameron , Lars-Peter Clausen , Olivier Moysan , Michael Hennerich X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1708092664; l=17054; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=CvwKiGjVNQppXuDRhWVxRThzbYj2LThOv82ZzfoS6lA=; b=fD0LGjImMZWkbx5tbX0KgGnaDK/Gg8OrS5XTEqKEJe8PRGnOKNsGzkzfxwX/sGrC9bSIGr1ge rkTWuGDK0AnCEKFW4xWR8S9C3X2KftiDzjGvZtfaDn5GFVHlTkRPeaA X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: Nuno Sa Reply-To: From: Nuno Sa This change adds support for the Analog Devices Generic AXI DAC IP core. The IP core is used for interfacing with digital-to-analog (DAC) converters that require either a high-speed serial interface (JESD204B/C) or a source synchronous parallel interface (LVDS/CMOS). Usually, some other interface type (i.e SPI) is used as a control interface for the actual DAC, while the IP core (controlled via this driver), will interface to the data-lines of the DAC and handle the streaming of data into memory via DMA. Because of this, it will register itself as an IIO backend. Signed-off-by: Nuno Sa --- drivers/iio/dac/Kconfig | 21 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/adi-axi-dac.c | 510 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 532 insertions(+) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 98e80e73fab5..d1634580f781 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -147,6 +147,27 @@ config AD9739A To compile this driver as a module, choose M here: the module will be called ad9739a. +config ADI_AXI_DAC + tristate "Analog Devices Generic AXI DAC IP core driver" + select IIO_BUFFER + select IIO_BUFFER_DMAENGINE + select REGMAP_MMIO + select IIO_BACKEND + help + Say yes here to build support for Analog Devices Generic + AXI DAC IP core. The IP core is used for interfacing with + digital-to-analog (DAC) converters that require either a high-speed + serial interface (JESD204B/C) or a source synchronous parallel + interface (LVDS/CMOS). + Typically (for such devices) SPI will be used for configuration only, + while this IP core handles the streaming of data into memory via DMA. + + Link: https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called adi-axi-dac. + config LTC2688 tristate "Analog Devices LTC2688 DAC spi driver" depends on SPI diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 7e39e0c218ca..8432a81a19dc 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_AD7293) += ad7293.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o obj-$(CONFIG_AD9739A) += ad9739a.o +obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o obj-$(CONFIG_CIO_DAC) += cio-dac.o obj-$(CONFIG_DPOT_DAC) += dpot-dac.o obj-$(CONFIG_DS4424) += ds4424.o diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c new file mode 100644 index 000000000000..58d01ecc0618 --- /dev/null +++ b/drivers/iio/dac/adi-axi-dac.c @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices Generic AXI DAC IP core + * Link: https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + * + * Copyright 2016-2024 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* + * Register definitions: + * https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map + */ + +/* Base controls */ +#define AXI_DAC_REG_CONFIG 0x0C +#define AXI_DAC_DISABLE BIT(6) + + /* DAC controls */ +#define AXI_DAC_REG_RSTN 0x0040 +#define AXI_DAC_RSTN_CE_N BIT(2) +#define AXI_DAC_RSTN_MMCM_RSTN BIT(1) +#define AXI_DAC_RSTN_RSTN BIT(0) +#define AXI_DAC_REG_CNTRL_1 0x0044 +#define AXI_DAC_SYNC BIT(0) +#define AXI_DAC_REG_RATECNTRL 0x004C +#define AXI_DAC_DRP_STATUS 0x0074 +#define AXI_DAC_DRP_LOCKED BIT(17) + +/* DAC Channel controls */ +#define AXI_DAC_REG_CHAN_CNTRL_1(c) (0x0400 + (c) * 0x40) +#define AXI_DAC_REG_CHAN_CNTRL_3(c) (0x0400 + (c) * 0x40) +#define AXI_DAC_SCALE_SIGN BIT(15) +#define AXI_DAC_SCALE_INT BIT(14) +#define AXI_DAC_SCALE_INT_NEG GENMASK(15, 14) +#define AXI_DAC_SCALE_FRAC GENMASK(13, 0) +#define AXI_DAC_REG_CHAN_CNTRL_2(c) (0x0404 + (c) * 0x40) +#define AXI_DAC_REG_CHAN_CNTRL_4(c) (0x040c + (c) * 0x40) +#define AXI_DAC_PHASE GENMASK(31, 16) +#define AXI_DAC_FREQUENCY GENMASK(15, 0) +#define AXI_DAC_REG_CHAN_CNTRL_7(c) (0x0418 + (c) * 0x40) +#define AXI_DAC_DATA_SEL GENMASK(3, 0) + +/* 360 degrees in rad */ +#define AXI_DAC_2_PI_MEGA 6283190 +enum { + AXI_DAC_DATA_INTERNAL_TONE, + AXI_DAC_DATA_DMA = 2, +}; + +struct axi_dac_state { + struct regmap *regmap; + struct device *dev; + /* Lock for synchronizing device register access. */ + struct mutex lock; + u64 dac_clk; + u32 reg_config; +}; + +static int axi_dac_frequency_read(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx, + unsigned long long sample_freq) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + u32 reg, __val; + u16 freq; + int ret; + + if (tone_idx > 1) { + dev_err(st->dev, "Not a valid tone: %u\n", tone_idx); + return -EINVAL; + } + + if (tone_idx) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + + ret = regmap_read(st->regmap, reg, &__val); + if (ret) + return ret; + + freq = FIELD_GET(AXI_DAC_FREQUENCY, __val); + *val = DIV_ROUND_CLOSEST_ULL(__val * sample_freq, BIT(16)); + + return 0; +} + +static int axi_dac_scale_read(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + u8 sign, integer; + u32 reg, __val; + u16 frac; + int ret; + + if (tone_idx > 1) { + dev_err(st->dev, "Not a valid tone: %u\n", tone_idx); + return -EINVAL; + } + + if (tone_idx) + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + + ret = regmap_read(st->regmap, reg, &__val); + if (ret) + return ret; + + frac = FIELD_GET(AXI_DAC_SCALE_FRAC, __val); + sign = FIELD_GET(AXI_DAC_SCALE_SIGN, __val); + integer = FIELD_GET(AXI_DAC_SCALE_INT, __val); + + *val2 = DIV_ROUND_CLOSEST_ULL((u64)frac * MICRO, AXI_DAC_SCALE_INT); + + if (integer && sign) + *val = -1; + else if (integer) + *val = 1; + else if (sign) + *val2 *= -1; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int axi_dac_phase_read(struct iio_backend *back, + const struct iio_chan_spec *chan, int *val, + int *val2, unsigned int tone_idx) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + unsigned int tmp; + u32 reg, __val; + u16 phase; + int ret; + + if (tone_idx > 1) { + dev_err(st->dev, "Not a valid tone: %u\n", tone_idx); + return -EINVAL; + } + + if (tone_idx) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + + ret = regmap_read(st->regmap, reg, &__val); + if (ret) + return ret; + + phase = FIELD_GET(AXI_DAC_PHASE, __val); + tmp = DIV_ROUND_CLOSEST_ULL((u64)phase * AXI_DAC_2_PI_MEGA, U16_MAX); + *val = tmp / MICRO; + *val2 = tmp % MICRO; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int axi_dac_frequency_write(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx, + unsigned long long sample_freq) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + u16 freq; + u32 reg; + int ret; + + if (val < 0 || !sample_freq || val > sample_freq / 2) { + dev_err(st->dev, "Invalid frequency: %d, sampling freq: %llu\n", + val, sample_freq); + return -EINVAL; + } + + if (tone_idx > 1) { + dev_err(st->dev, "Not a valid tone: %u\n", tone_idx); + return -EINVAL; + } + + if (tone_idx) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + + freq = DIV64_U64_ROUND_CLOSEST((u64)val * BIT(16), sample_freq); + + guard(mutex)(&st->lock); + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_FREQUENCY, freq); + if (ret) + return ret; + + /* synchronize channels */ + return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); +} + +static int axi_dac_scale_write(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + u32 scale = 0, tmp, reg; + int ret; + + if (tone_idx > 1) { + dev_err(st->dev, "Not a valid tone: %u\n", tone_idx); + return -EINVAL; + } + + /* format is 1.1.14 (sign, integer and fractional bits) */ + switch (val) { + case 1: + scale = FIELD_PREP(AXI_DAC_SCALE_INT, 1); + break; + case -1: + scale = FIELD_PREP(AXI_DAC_SCALE_INT_NEG, 3); + break; + case 0: + if (val2 < 0) { + scale = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1); + val2 *= -1; + } + break; + default: + return -EINVAL; + } + + tmp = DIV_ROUND_CLOSEST_ULL((u64)val2 * AXI_DAC_SCALE_INT, MICRO); + scale |= FIELD_PREP(AXI_DAC_SCALE_FRAC, tmp); + + if (tone_idx) + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + + guard(mutex)(&st->lock); + ret = regmap_write(st->regmap, reg, scale); + if (ret) + return ret; + + /* synchronize channels */ + return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); +} + +static int axi_dac_phase_write(struct iio_backend *back, + const struct iio_chan_spec *chan, int val, + int val2, unsigned int tone_idx) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + u32 phase, reg; + int ret; + + if (tone_idx > 1) { + dev_err(st->dev, "Not a valid tone: %u\n", tone_idx); + return -EINVAL; + } + + phase = val * MILLI + val2; + + phase = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA); + + if (tone_idx) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + + guard(mutex)(&st->lock); + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE, + FIELD_PREP(AXI_DAC_PHASE, phase)); + if (ret) + return ret; + + /* synchronize channels */ + return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); +} + +static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (data) { + case IIO_BACKEND_INTERNAL_CW: + return regmap_update_bits(st->regmap, + AXI_DAC_REG_CHAN_CNTRL_7(chan), + AXI_DAC_DATA_SEL, + AXI_DAC_DATA_INTERNAL_TONE); + case IIO_BACKEND_EXTERNAL: + return regmap_update_bits(st->regmap, + AXI_DAC_REG_CHAN_CNTRL_7(chan), + AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA); + default: + return -EINVAL; + } +} + +static struct iio_buffer *axi_dac_request_buffer(struct iio_backend *back, + struct iio_dev *indio_dev) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + struct iio_buffer *buffer; + const char *dma_name; + int ret; + + if (device_property_read_string(st->dev, "dma-names", &dma_name)) + dma_name = "tx"; + + buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name); + if (IS_ERR(buffer)) { + dev_err(st->dev, "Could not get DMA buffer, %ld\n", + PTR_ERR(buffer)); + return ERR_CAST(buffer); + } + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + iio_buffer_set_dir(buffer, IIO_BUFFER_DIRECTION_OUT); + + ret = iio_device_attach_buffer(indio_dev, buffer); + if (ret) + return ERR_PTR(ret); + + return buffer; +} + +static void axi_dac_free_buffer(struct iio_backend *back, + struct iio_buffer *buffer) +{ + iio_dmaengine_buffer_free(buffer); +} + +static int axi_dac_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + unsigned int __val; + int ret; + + guard(mutex)(&st->lock); + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN, + AXI_DAC_RSTN_MMCM_RSTN); + if (ret) + return ret; + /* + * Make sure the DRP (Dynamic Reconfiguration Port) is locked. Not all + * designs really use it but if they don't we still get the lock bit + * set. So let's do it all the time so the code is generic. + */ + ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS, __val, + __val & AXI_DAC_DRP_LOCKED, 100, 1000); + if (ret) + return ret; + + return regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN, + AXI_DAC_RSTN_RSTN | AXI_DAC_RSTN_MMCM_RSTN); +} + +static void axi_dac_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + guard(mutex)(&st->lock); + regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0); +} + +static const struct iio_backend_ops axi_dac_generic = { + .enable = axi_dac_enable, + .disable = axi_dac_disable, + .request_buffer = axi_dac_request_buffer, + .free_buffer = axi_dac_free_buffer, + .read_frequency = axi_dac_frequency_read, + .write_frequency = axi_dac_frequency_write, + .read_scale = axi_dac_scale_read, + .write_scale = axi_dac_scale_write, + .read_phase = axi_dac_phase_read, + .write_phase = axi_dac_phase_write, + .data_source_set = axi_dac_data_source_set, +}; + +static const struct regmap_config axi_dac_regmap_config = { + .val_bits = 32, + .reg_bits = 32, + .reg_stride = 4, + .max_register = 0x0800, +}; + +static int axi_dac_probe(struct platform_device *pdev) +{ + const unsigned int *expected_ver; + struct axi_dac_state *st; + void __iomem *base; + unsigned int ver; + struct clk *clk; + int ret; + + st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + expected_ver = device_get_match_data(&pdev->dev); + if (!expected_ver) + return -ENODEV; + + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + st->dev = &pdev->dev; + st->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &axi_dac_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + /* + * Force disable the core. Up to the frontend to enable us. And we can + * still read/write registers... + */ + ret = regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADI_AXI_REG_VERSION, &ver); + if (ret) + return ret; + + if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { + dev_err(&pdev->dev, + "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", + ADI_AXI_PCORE_VER_MAJOR(*expected_ver), + ADI_AXI_PCORE_VER_MINOR(*expected_ver), + ADI_AXI_PCORE_VER_PATCH(*expected_ver), + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + return -ENODEV; + } + + /* Let's get the core read only configuration */ + ret = regmap_read(st->regmap, AXI_DAC_REG_CONFIG, &st->reg_config); + if (ret) + return ret; + + /* + * Default rate to 1 so the sampling frequency will be the same as the + * digital interface clock which should be the same as the frontend + * sampling clock/frequency. When this is not true, the frontend will + * have to explicitly set a new frequency and thus rate. + */ + ret = regmap_write(st->regmap, AXI_DAC_REG_RATECNTRL, 1); + if (ret) + return ret; + + mutex_init(&st->lock); + ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); + if (ret) + return ret; + + dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + + return 0; +} + +static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b'); + +static const struct of_device_id axi_dac_of_match[] = { + { .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info }, + {} +}; +MODULE_DEVICE_TABLE(of, axi_dac_of_match); + +static struct platform_driver axi_dac_driver = { + .driver = { + .name = "adi-axi-dac", + .of_match_table = axi_dac_of_match, + }, + .probe = axi_dac_probe, +}; +module_platform_driver(axi_dac_driver); + +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("Analog Devices Generic AXI DAC IP core driver"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); +MODULE_IMPORT_NS(IIO_BACKEND);