From patchwork Thu Mar 28 13:22:25 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: 13608525 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 760EE7EF1C; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=d5v1BEl7FZaXmMPJZUP9oTFJD1Z/q2aZgpB22wDCI/o7u74nuKfBMLhHALngz7dRolcPU/MwnZZjVG0PH+duwlhzQgjDaYlntFJZcw90Fpsgziu3RmD9q3M0u1Vqj20azYO/K+36wx7jC4H1U5cKVReYe5/MCOHvW3pfKSx4ovU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=Zhpd8WzkLG2F5zW5Uvp82LSK9+vK4KrStNMmwiVeLwg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lx5Ypd5MVVswokmVfCMi5PURmhpUXDl35NLm4y1isT8iI5hmhFnqUif3bpAzWNsxB2QifqZ3IA/Jh/u1CTlDOy1hIueOopsEKC/sjzUvuQB3y0NbegpNyCoqLRMImNyppRHDWBzWGu5xqmqBSAtB6iYMY2tCuuQQeXZGmeUnWLQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fWHB4HcF; 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="fWHB4HcF" Received: by smtp.kernel.org (Postfix) with ESMTPS id 1B89CC43390; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=Zhpd8WzkLG2F5zW5Uvp82LSK9+vK4KrStNMmwiVeLwg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=fWHB4HcF5mZFa2aNtlc0W980cIM0NEIQvsluRxl9D0CBoQPm73jippPIGSFXUk0SU PQVuhryKV0VzF4PdbvcfU6SSBL913HqVIRa8X0Qsw4uJVJ7lvBPL3j9lYTI9SmM4jJ 7mJjixgfhef44yBBprWoEWnPgoYH10FDVsHn1r7442qvsB5EoM6ELwlOBNOJKTE6S/ kNZLW40EZQ8aUIwLmB/3Z0M9SwXlSut/mYv6J8S3vcqaa9DooE0oB6grWLN4fkrJP2 93r5DwuXjugc+q9X1xxTmI/AVz8E1zTsH0r2Xr+LyQGpuphj0CFbXIox+HP6UKCeth v/g3oOSd7NLXg== 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 070ABC54E67; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:25 +0100 Subject: [PATCH 01/10] iio: buffer: add helper for setting direction Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240328-iio-backend-axi-dac-v1-1-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=1414; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=lt7Z8RtIdxVgrFaJw2wbb9LfqTru+QeAjVGlcUx2ZmQ=; b=YLdcKzTC+ACwMMpn0xzv2NB3s4QralrrXazg9t1SIQP7uy/w+RRq3Rgl7jmXevXFSEwPUZ2C1 FVOvjF3XC2FCSohkp+rZmxd4a49eEsMvkPBYCx6aiO52KTdDgokTXhG 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: nuno.sa@analog.com From: Nuno Sa Simple helper for setting the buffer direction when it's allocated using iio_dmaengine_buffer_alloc(). Signed-off-by: Nuno Sa --- drivers/iio/industrialio-buffer.c | 7 +++++++ include/linux/iio/buffer.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 1d950a3e153b..4b1ca6ad86ee 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1956,6 +1956,13 @@ void iio_buffer_put(struct iio_buffer *buffer) } EXPORT_SYMBOL_GPL(iio_buffer_put); +void iio_buffer_set_dir(struct iio_buffer *buffer, + enum iio_buffer_direction dir) +{ + buffer->direction = dir; +} +EXPORT_SYMBOL_GPL(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..7e70bb5adc01 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 dir); + #endif /* _IIO_BUFFER_GENERIC_H_ */ From patchwork Thu Mar 28 13:22:26 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: 13608526 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 7DB787EF0D; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=tRbBXB78kRbMw2H07uKicEl5Ly6Gls0qkxec3QWQcU3Js50mH0IxGkvlzaYvxgPX+exqVju36EljJXMxJJhKr8qBx9+kU/x2PO9lbnUjJz/ymLy9dS88uYLeIt2k48gn2lR8T1NgR5RnZ6VEpWXHspZqLruITHL7t1kKtmtUVSA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=LRS3rt6TicXfYuFlOhhxQs3qLQWMSYhItKcuxXNBxbc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=He6/Q+cy+3sBwlZs61usfRPFxGTb90/tqkjXqG/mXhvQafLVuHVhtCuf622p3hf55GsBLn4qKJxuXhJowtHiaHj0U+6cppYcifHPlZjETFF7/9kJXYTWr1zv/fti1fAKuYA2MosFSrZ4rHUkwuPbCL8Lxrmx44BpR9zktMfS1l0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=V+/FkLRw; 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="V+/FkLRw" Received: by smtp.kernel.org (Postfix) with ESMTPS id 28335C433F1; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=LRS3rt6TicXfYuFlOhhxQs3qLQWMSYhItKcuxXNBxbc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=V+/FkLRwk+4ZvYVkRyr7Sz1KB448tmnZtwq0z1V0mHMLhpJOxXAJXeeKLlLDo9fPm jYTPMGSCZF9ZvQs/n3watkSP8xqHLAGulneInuXtibkB3QPD998y2xf0PnEN2ZD6UQ wfpIc774v1ERjuWpv5djmdOIT/BfY6fK7UC+74+UIMxE+3lmQY7IbmZy5fhIhC6EwO 4pEHUWf/xhd8z2EjXZaJWRnYvWsyt3jABq+5vaNxTz47Kp7n4bKicfcFmxI+py06We P4ozGbGblsY0N6bCYOqqJzoCrk0b48pRw8Hk6jkHcVgcAlg3RTq8Wk/MSGH8wzGpFA ZUj5bmFy5O+/A== 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 12CBCCD1287; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:26 +0100 Subject: [PATCH 02/10] 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: <20240328-iio-backend-axi-dac-v1-2-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Paul Cercueil , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=3293; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=pnGz0IvIMOvc3W8GugiHOr2smQMJ1XHymguYmuxH0E8=; b=kZyFUV24Qavk9g5njiC2rh85qnccUwghLRpCof5xrJYL8VffLa8vs8sxnB+GoQHYw0T550tPN B+d3HcyykbTAyh+3mesKPNtS2UDDTFPB39JhpxhtHfSzvhxPFWdSmpC 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: nuno.sa@analog.com 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 Signed-off-by: Nuno Sa --- 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 Thu Mar 28 13:22:27 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: 13608528 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 921317F7CC; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=ZnB7z05p5SFCjqWTkleLw09+uvScTWKG19zguqPwQ627zMqZOiOv4E84h3OAAQrQpCuUXBZMZ0YDNpE6O9+ZfbRfVmnY0bquxNOHtr42lcFu+fM3TZoRHK85rq+V6EEwlQcmnWhnv+ENAzvez9x5sVtRTfgZvxdHchkdjs4qF8c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=L8OTmKgFPYqQ/Olv8v4xj7GWpzhnA1unLSnzP1fJ+t0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UnEwpg/j4jBfeZorrOFflSiYhFpX1NAO7g0NNh+RmEx81AjTV3AKus/MJtkSS4kKAyZ6yc27UA+h+z0ffswOLbBEWBh5XL9W2JKx6IF4V09YHz3Ustbvc8slJGjA4EIFA/SXMxO2/l5OnzXk/ZWWM6gQOpEyVzvy7Ob4HCN+Il8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZHQk7lXt; 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="ZHQk7lXt" Received: by smtp.kernel.org (Postfix) with ESMTPS id 31963C43399; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=L8OTmKgFPYqQ/Olv8v4xj7GWpzhnA1unLSnzP1fJ+t0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ZHQk7lXt1L+h/SwIdpsbHgRLADUyVeXv7Uvql1GCtZXKGZh6bCfrdcdj0os2e8ouQ XaWnqgA2PcY3yLdbmnzvnW6FwZ3PfN9dWA3RbN5Tx/0Fhw4H4Zke25KSLjnOqNUNSw TDPAH6ksQQEJfcTUB7WzDhreGy2calV/9vUtfhH8z1xZVrGo6U502yv/cpF8EqPMWe 21uBMwAxAR+tKsds46x4WPjTWDtAdd9x95IR3XQhplWXfabBKuQNSWl1/S4eQsGOjT IkAAjO+kFtJMKH8Z8akjPFFjMfQ2LFlM1qxctlzg54KXTOus0AORri57ILAtM6zh13 zUPtjfOw2v+aw== 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 214D2CD1288; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:27 +0100 Subject: [PATCH 03/10] 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: <20240328-iio-backend-axi-dac-v1-3-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Paul Cercueil , Alexandru Ardelean , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=6611; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=uC5b6sW5lAaLeXnzVX0KMOgnvrGo+tKae+dh5KeGfHM=; b=sGXo3t/rSU1lm0VNdzF+lj0zZWufNqMF8Wi+8vZSBt0kfk/nAt7UAOkjXShHyyRV/LrGkj9VJ nXh4TC9yISkBf/mNC2DKWB/XMusOAOW8uAoktsgBI1CRKD1D0vhfwvn 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: nuno.sa@analog.com 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 Signed-off-by: Nuno Sa --- 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 Thu Mar 28 13:22:28 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: 13608527 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 9210E7F48B; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=pB70XYP36lafRrX1KuAHPW5TpR9y0DQx9UOKFuUFALc6I4JP6pzSfN5cugGVLrVsSN26wS+xIPzPzoZiaS8dXqMoT1J8xMYjQ/9U8arbaQikElF3hund8lKuvMwAlR0O+fNeGsFVEKQfFeZo8/XvPuxZeDfkgNc5+KBc43NMGAA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=U7eugRZ0onsk1ecBmL8dcjYyAcI4CEkYadmrnw5LOJw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Pr0y5tG2w40jrrBS0nMg+JwSxZ334ndq5yBj1FjzAcOYa49gbEgdfBovIkCrL3geAAUreCwtxz2YxOKSb7sN6aySgZhAA22OTw3DPY4WH94l8drR7QznREItQW2DcHoDwi0Fpbck3n1lzpbI8hvErxe2vksACUCQrTwhKg5/XL8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OA3YnRYU; 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="OA3YnRYU" Received: by smtp.kernel.org (Postfix) with ESMTPS id 376A3C433A6; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=U7eugRZ0onsk1ecBmL8dcjYyAcI4CEkYadmrnw5LOJw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=OA3YnRYUQk0ncNDbU4eo4RppfK/2//v/qGxEFdmuD/09fvUMpEVrZJratl/bHYctn 50HTNhzvQw78x8hAvV56KQslGJbNgjStUwqQgtjCBhc9I3pdG3xssjOnDpDVYZ0afD UQRrnfZOn78JNQF+2hKZU8R1UZbir6EJSygYXX3Bd02WnuJOAhoyd05skbCxKIlxcL SmIIoUs4ZZMHDkC5n1pf9uheH1Sd0h+zYzaGj6dmS0EvdoWbf+t545OEhxaz3uoDWi t8mTMgp5WXD9uSJTSRjSeJz5lUKZvuyu95GNB5NPMKk/3BXJvOiV7jRj45u+w4BAzh +25eAJkKB1hdw== 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 2E1CDCD1284; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:28 +0100 Subject: [PATCH 04/10] 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: <20240328-iio-backend-axi-dac-v1-4-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Paul Cercueil , Alexandru Ardelean , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=3320; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=K0DaW1NvLTF6FP5FkoLaCwonpUuBlGRixF54Kc6llO8=; b=qKgYfHbOONfuB8LpNUZbEdfpaPdzPgaN1hnDNLjaQ6jJDu9/WCIjuUURlRVRGRYTAXNJLN8ZZ 0q+rWBup17JAckjBnFwFxvBAMpuNFnsg/FTA/VMSXGbxUku/0QpW8xr 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: nuno.sa@analog.com 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 | 6 +++++- 2 files changed, 24 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..f0d750ce2880 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,8 @@ 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 Thu Mar 28 13:22:29 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: 13608533 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 C6FC680BE3; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=Ox/zSJT0Js16I63VrcSNKAP9LNL8kqrHFgTU4rF5ylT5peXpp9IgXHXwGN+gOLQdirvpyhh4fcmhfrkVhMOLn4GYns8lh9eMe4dde08ELyXJPkY6cPz8zQ3uh9Mh8ePdY3CJWa1yetrmDeYnISUrTo/SCZTp3tmWHWWD5GK/bss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=5NCTwqp0/VL05f5aoUnTF7pYtP3n/rPaf1XK2xqJjGM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dSK3QYZcmrLFnBH4oStVL6a3rUagBz8Bd04ShUHDuvicTx43ic0feKOSNNVyoaebWeL8TuHTUFXAHZ1BOr2nP4OeeI/jg8Ad4mtF1reR8ZFiVzDTG8OVRJD84zamox9kZ3Mkl71MMWhx+hfUd6GVw77jXciYxslKeUgdcW7by+M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PYSjdgag; 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="PYSjdgag" Received: by smtp.kernel.org (Postfix) with ESMTPS id 4A81DC43601; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=5NCTwqp0/VL05f5aoUnTF7pYtP3n/rPaf1XK2xqJjGM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=PYSjdgaghJ/HsWcaHxjfxyp7a0u3GHpFnasPbqr0Kbp29pPsilVbn9BIwiLUnpslL Cl2kRfKxBwvA3X9jwzZ8RCEpuUOhOTWMx7EQ9sf+USknbuxTfJQPtUZReAIILythcj 7BG4KaJ1HZVRuh2/UeAYgzSS2fvG2OiCiAY2FeHUXoy6BGz9shpbDCEvc3r5K8Mpio zVC2pHWwAIjl1Ciz4hrORsNKiEyyeuSnC5tqJkZwVtIeBJ9qjSW9l1Xrr6ZIfjvwMR nOZ/rT3sgNSuk6FPvQYvMKpdVvDVdwBcRXkeVv/Fm81bTvqgT5lDLieY9WAgcFKoXL uxGvslQlE5kkQ== 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 415F4C54E67; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:29 +0100 Subject: [PATCH 05/10] 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: <20240328-iio-backend-axi-dac-v1-5-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Paul Cercueil , Alexandru Ardelean , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=1350; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=fAbl1tHATN4k7f5YdDrD3IPPBFiik7XcUZ987EP1q04=; b=5T0qqbYggFoRGj5numeuSXuEjERRT8gvitBj7MBegHH0651jwhxZ8K8Uq5eMnUQJ8xpyk4KJD RmjyfQZZywKDUgmD+85d8rhnz9974hCEZKnpG2thnfd24wF65X6LF19 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: nuno.sa@analog.com 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 Signed-off-by: Nuno Sa --- 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 Thu Mar 28 13:22:30 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: 13608532 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 C6C628063E; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=bG31EeSDTkOjAi+iJxli1JutlF80MKdClApjsiF1LLmDpVmIsemaF5kVEJGry32ddIm3bAaz0RGjMRS5mcM3owQYA8LN7noR+A1GRvegTPne4bEbBlJiTq7Yk3YnDgUGuksQUIz6iCcUb6UEzv4fBsbA9HtCuLsMtI6dHhg2s4k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=nib2Y7Os2dV/woyZnjR3ZjQ8QPw+xJ6kxTqaC4x5Lo0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VSD4cXXgjT4tFTLjkJwrinGinBvp2ivEzqVwM2YIyTuJom2Z6LrOg/utecR3vH4GGGljypnrr3xzVOV25W0kPFmxb7zW2u2y2MF1rEuuBn/D0bMPXOHpLQFLeaK/yva1Iz/+yG7B3NrvOMCXFLDkWuHQGyvJhKiihslf4hKN0as= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YqsmlT8z; 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="YqsmlT8z" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5EB3EC41679; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=nib2Y7Os2dV/woyZnjR3ZjQ8QPw+xJ6kxTqaC4x5Lo0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=YqsmlT8zuty3E9xLXykGe8omgN/RIEqWp7pm15vjNjMXT+RB/0blhU8esx+WKeOHx duyRJRwMegzH05wNB9gV0Yjctmq96mtCWkteX/5v5Arh37ph5qv+XmOEEcX73GkGfP JU5A5IP/MnhB4SlYUhIb6Nv9RY9XPVc05x1nK1ZcrxGub/Go3UXutNU0godP29uqIq NjOGTbKojc5XDxuR1m2DnqdP9Zy1EArkUOYj1wicIrwuW2gAiXp6/C4deG520WihKA fMIW6YyxV91jsYKrgr+VbUHdbpGDbumDHFMGTsgYKR6QpNnMGJdP51gi1X2qWSyqEb hkKBt+5hiWz6Q== 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 548B5CD128A; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:30 +0100 Subject: [PATCH 06/10] dt-bindings: iio: dac: add bindings doc for AXI DAC driver Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240328-iio-backend-axi-dac-v1-6-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=2556; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=zVVn2JnKO8KSPJ/lC/YKERxJrRCXPzQ6KY6j3DeQTRc=; b=2YAmZQtCOk7TFaRM8YKsa/zmMhqJPrPnyxlQpo3NZDcZX3co7rXYlsQGP2m19xL/pWr79F1gU +V8ep35nOU8AQH8VTcC7Hk8GEG3E/jthvmgyUvlssCQ6mYilOkPVwCl 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: nuno.sa@analog.com From: Nuno Sa This adds the bindings documentation for the AXI DAC driver. Signed-off-by: Nuno Sa --- .../devicetree/bindings/iio/dac/adi,axi-dac.yaml | 62 ++++++++++++++++++++++ MAINTAINERS | 7 +++ 2 files changed, 69 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml new file mode 100644 index 000000000000..1018fd274f04 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,axi-dac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AXI DAC IP core + +maintainers: + - Nuno Sa + +description: | + Analog Devices Generic AXI DAC IP core for interfacing a DAC device + with a high speed serial (JESD204B/C) or 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 this IP core will interface + to the data-lines of the DAC and handle the streaming of data into + memory via DMA. + + https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + +properties: + compatible: + enum: + - adi,axi-dac-9.1.b + + reg: + maxItems: 1 + + dmas: + maxItems: 1 + + dma-names: + items: + - const: tx + + clocks: + maxItems: 1 + + '#io-backend-cells': + const: 0 + +required: + - compatible + - dmas + - reg + - clocks + +additionalProperties: false + +examples: + - | + dac@44a00000 { + compatible = "adi,axi-dac-9.1.b"; + reg = <0x44a00000 0x10000>; + dmas = <&tx_dma 0>; + dma-names = "tx"; + #io-backend-cells = <0>; + clocks = <&axi_clk>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index a7287cf44869..2137eb452376 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1399,6 +1399,13 @@ F: sound/soc/codecs/adav* F: sound/soc/codecs/sigmadsp.* F: sound/soc/codecs/ssm* +ANALOG DEVICES INC AXI DAC DRIVER +M: Nuno Sa +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml + ANALOG DEVICES INC DMA DRIVERS M: Lars-Peter Clausen S: Supported From patchwork Thu Mar 28 13:22:31 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: 13608529 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 D668180BF0; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=UB3oQvRq4C/yXgpG2t6Id7irK8WTwEDHpuSzeb9aKqExLAbO1CO7ChEZf5R/J21FoS6G7enFsn3ciBp8gCvrSvLo4OtWoUUbCll1AVZbMCS5J7DN/AxuDpz3nY+XsqAhOFZowf02Vv8FadWy1yvo9fQxHiFBoxIpC03637xl4CU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=xD4mzL9DBmhmXkZrypEko4lFxsEy0mYudTVLVup3SgU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XZ0V36UCKHoDEfYXfIbYc3t16obCQ/vkrH4HAMH6dNAL6xtFxEnl5nfvgh4zT6hxPiRxE2VjnD0A4AsIKep1yYeF0hxE7EYLB8MmWKIDnWbq5FqdJhTTM+DVC4wO6PGOKddpR+GKkNY512kWpN7ciEgTvsNSaeCTilDU8y/QxmY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nAKVW0pH; 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="nAKVW0pH" Received: by smtp.kernel.org (Postfix) with ESMTPS id 703B5C32788; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=xD4mzL9DBmhmXkZrypEko4lFxsEy0mYudTVLVup3SgU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=nAKVW0pHfeci3QN9h8bKeZ8BfU7WdoG0FSDIsnXxjwQMJqqEUhn0I8+hXGEY5p/iV un2SswCYrL9TxHsoLUHlcJ8FgQihVQigR3jATjBM+w4Znz9IqcSfNkqBijly+Eo+WD pXBXWj8jsNIxvyjEsCpNDHroLVuSJ164OA4UvOs52Gr7A5peuwgHnRMg3ze9eBz9Mu xfAO/0QuNrZu5rVnXK0ejJR/xBO5O9hNQon4lNKwp4bTYfGtwXFD6yaP9TZZw3IxR+ 8VsItl0E+NbZ63dSHHLX/ozPH7nnEoKiOx0EaQUmKTykyyMWj0uuSaOQ2QZSIFwiHC muTe/z7EDwKNA== 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 69D2DCD1283; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:31 +0100 Subject: [PATCH 07/10] dt-bindings: iio: dac: add bindings doc for AD9739A Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240328-iio-backend-axi-dac-v1-7-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=3209; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=TE1EDYOt04eltj6msTlmY+mlUAyPqDFwW+KyyJ0QXLE=; b=+z5TTXiIpoIbMI/90ZEzXqH9KKeD/j57PmBH4iqcpJdLju0YEWY28zwvGZNRhcCz4Y+6FQf50 O7PWdgpFjS8BOw5qQ5lWjo4WmGF3GCklKm3boh0sFFghKMkJ1qC+vs7 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: nuno.sa@analog.com From: Nuno Sa This adds the bindings documentation for the 14 bit RF Digital-to-Analog converter. Signed-off-by: Nuno Sa --- .../devicetree/bindings/iio/dac/adi,ad9739a.yaml | 88 ++++++++++++++++++++++ MAINTAINERS | 8 ++ 2 files changed, 96 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml new file mode 100644 index 000000000000..24bcec763a9b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad9739a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD9739A RF DAC + +maintainers: + - Dragos Bogdan + - Nuno Sa + +description: | + The AD9739A is a 14-bit, 2.5 GSPS high performance RF DACs that are capable + of synthesizing wideband signals from dc up to 3 GHz. + + https://www.analog.com/media/en/technical-documentation/data-sheets/ad9737a_9739a.pdf + +properties: + compatible: + enum: + - adi,ad9739a + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + vdd_3_3-supply: + description: 3.3V Digital input supply. + + vdd-supply: + description: 1.8V Digital input supply. + + vdda-supply: + description: 3.3V Analog input supply. + + vddc-supply: + description: 1.8V Clock input supply. + + io-backends: + maxItems: 1 + + adi,full-scale-microamp: + description: This property represents the DAC full scale current. + minimum: 8700 + maximum: 31700 + +required: + - compatible + - reg + - clocks + - io-backends + - vdd_3_3-supply + - vdd-supply + - vdda-supply + - vddc-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "adi,ad9739a"; + reg = <0>; + + clocks = <&dac_clk>; + + io-backends = <&iio_backend>; + + vdd_3_3-supply = <&vdd_3_3>; + vdd-supply = <&vdd>; + vdda-supply = <&vdd_3_3>; + vddc-supply = <&vdd>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 2137eb452376..76e872e320d7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1234,6 +1234,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml F: drivers/iio/adc/ad7780.c +ANALOG DEVICES INC AD9739a DRIVER +M: Nuno Sa +M: Dragos Bogdan +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml + ANALOG DEVICES INC ADA4250 DRIVER M: Antoniu Miclaus L: linux-iio@vger.kernel.org From patchwork Thu Mar 28 13:22:32 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: 13608530 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 D66C780BF4; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=RJthlyDx0A1A0rH+mz3JefTKAGEtgmzd0YAGJ5yKxEKyYWPzYStSIlprXJrxgt+TQGVZCUkXYnHLNjfSg1S7fJ6+f3Qvo+Zs88Evo9aMlicEnpUr+j78Qb9IkpXInALGAvh9H88PpJolBmmiZxHR525SHTGWHOB+TxEYSeSzk8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=zchI4s+oG36h0qA+IWC4oD50p5rN0c8B1V2I1xsqhnw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tAaHd8o0uAgb7eqQElQv6JKa41sgnIXpjrqqbRJRv/hesYvzUfVYNz5OWt5tZAf8elr9v4f7j3BD/9/06CLJQ2y7hLqkAzQx57sTYqj1E2vYFKeXs62ScGWX0+jZxVJrHSsD11qn1gebDwdzuYFMReD/RLQstgIClX/my6Zfluo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MgXVrjiV; 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="MgXVrjiV" Received: by smtp.kernel.org (Postfix) with ESMTPS id 90760C3278C; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=zchI4s+oG36h0qA+IWC4oD50p5rN0c8B1V2I1xsqhnw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=MgXVrjiV3dPofEe6vK6SkIZuMJL1F+nFJpfCCa0lL4wGidl2k5cW0pBd5XprnyJe3 ey6B+gLxmZawZ5xf3nk4SIT7gPmw2wwzkvkLALpJZkRF4qnoUE1+ltRf5VrdSCSApN nUeX/Q3vW6DIk3ssznBF42sHyyMeFeg7CIp6LMSGq2L7EMGuMU4eI+fdw/zHoyHgS3 RD/NZ1l0l5zOBn3dEFhcgtyru/Bk+SyLbfSAbg4DVg2MXlJMTdASlERS3K96RG8Jwn RdBF9zjuq6FYKmRu48jZ7F0Iegubblw3WOvPwMTZgwiMeiGUnrrdexSO4Tt5nqBu8Q sTOX49Z7HHeSw== 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 876ECCD1284; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:32 +0100 Subject: [PATCH 08/10] iio: backend: add new functionality Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240328-iio-backend-axi-dac-v1-8-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=10519; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=7tO0Yxz4B8NnjPj8QREz6EaLoC8LjeYSjQuvStb9dNo=; b=Q+Ea9/YbCHhtw91DmLIZQh1erOUZseAKnqc1KzWH3FjwpRm1wZRXr4GXDpTexiT8POcDCscef vInGjDL8yF4DSjJmsAGgRfRAp+wmyToW2z6OkiDEajumJFA4t2jsAfU 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: nuno.sa@analog.com From: Nuno Sa This adds the needed backend ops for supporting a backend inerfacing with an high speed dac. The new ops are: * data_source_set(); * set_sampling_freq(); * extend_chan_spec(); * ext_info_set(); * ext_info_get(). Also to note the new helpers that are meant to be used by the backends when extending an IIO channel (adding extended info): * iio_backend_ext_info_set(); * iio_backend_ext_info_get(). Signed-off-by: Nuno Sa --- drivers/iio/industrialio-backend.c | 144 +++++++++++++++++++++++++++++++++++++ include/linux/iio/backend.h | 49 +++++++++++++ 2 files changed, 193 insertions(+) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 2fea2bbbe47f..0a26dd8c6343 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,44 @@ int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, } EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); +/** + * iio_backend_data_source_set - Select data source + * @back: Backend device + * @chan: Channel number + * @data: Data source + * + * A given backend may have different sources to stream/sync data. This allows + * to choose that source. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +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); + +/** + * iio_backend_set_sampling_freq - Set channel sampling rate + * @back: Backend device + * @chan: Channel number + * @sample_rate: Sample rate + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, + u64 sample_rate) +{ + return iio_backend_op_call(back, set_sample_rate, chan, sample_rate); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, IIO_BACKEND); + static void iio_backend_free_buffer(void *arg) { struct iio_backend_buffer_pair *pair = arg; @@ -231,6 +270,111 @@ int devm_iio_backend_request_buffer(struct device *dev, } EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); +/** + * iio_backend_ext_info_get - IIO ext_info read callback + * @indio_dev: IIO device + * @private: Data private to the driver + * @chan: IIO channel + * @buf: Buffer where to place the attribute data + * + * This helper is intended to be used by backends that extend an IIO channel + * (trough iio_backend_extend_chan_spec()) with extended info. In that case, + * backends are not supposed to give their own callbacks (as they would not + * a way to get te backend from indio_dev). This is the getter. + * + * RETURNS: + * Number of bytes written to buf, negative error number on failure. + */ +ssize_t iio_backend_ext_info_get(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct iio_backend *back = iio_device_get_drvdata(indio_dev); + + return iio_backend_op_call(back, ext_info_get, private, chan, buf); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, IIO_BACKEND); + +/** + * iio_backend_ext_info_set - IIO ext_info write callback + * @indio_dev: IIO device + * @private: Data private to the driver + * @chan: IIO channel + * @buf: Buffer holding the sysfs attribute + * @len: Buffer length + * + * This helper is intended to be used by backends that extend an IIO channel + * (trough iio_backend_extend_chan_spec()) with extended info. In that case, + * backends are not supposed to give their own callbacks (as they would not + * a way to get te backend from indio_dev). This is the setter. + * + * RETURNS: + * Buffer length on success, negative error number on failure. + */ +ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct iio_backend *back = iio_device_get_drvdata(indio_dev); + + return iio_backend_op_call(back, ext_info_set, private, chan, buf, len); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, IIO_BACKEND); + +/** + * iio_backend_extend_chan_spec - Extend an IIO channel + * @indio_dev: IIO device + * @back: Backend device + * @chan: IIO channel + * + * Some backends may have their own functionalities and hence capable of + * extending a frontend's channel. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_extend_chan_spec(struct iio_dev *indio_dev, + struct iio_backend *back, + struct iio_chan_spec *chan) +{ + const struct iio_chan_spec_ext_info *ext_info = chan->ext_info; + int ret; + + ret = iio_backend_op_call(back, extend_chan_spec, chan); + if (ret) + return ret; + /* + * Let's keep things simple for now. Don't allow to overwrite the + * frontend's extended info. If ever needed, we can support appending + * it. + */ + if (ext_info && chan->ext_info != ext_info) + return -EOPNOTSUPP; + if (!chan->ext_info) + return 0; + /* + * !\NOTE: this will break as soon as we have multiple backends on one + * frontend and all of them extend channels. In that case, the core + * backend code has no way to get the correct backend given the + * iio device. + * + * One solution for this could be introducing a new backend + * dedicated callback in struct iio_info so we can callback into the + * frontend so it can give us the right backend given a chan_spec. + */ + iio_device_set_drvdata(indio_dev, back); + + /* Don't allow backends to get creative and force their own handlers */ + for (ext_info = chan->ext_info; ext_info->name; ext_info++) { + if (ext_info->read != iio_backend_ext_info_get) + return -EINVAL; + if (ext_info->write != iio_backend_ext_info_set) + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, 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..09ff2f8f9fd8 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,26 @@ 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 +}; + +/** + * IIO_BACKEND_EX_INFO - Helper for an IIO extended channel attribute + * @_name: Attribute name + * @_shared: Whether the attribute is shared between all channels + * @_what: Data private to the driver + */ +#define IIO_BACKEND_EX_INFO(_name, _shared, _what) { \ + .name = (_name), \ + .shared = (_shared), \ + .read = iio_backend_ext_info_get, \ + .write = iio_backend_ext_info_set, \ + .private = (_what), \ +} + /** * struct iio_backend_data_fmt - Backend data format * @type: Data type. @@ -35,8 +56,13 @@ struct iio_backend_data_fmt { * @chan_enable: Enable one channel. * @chan_disable: Disable one channel. * @data_format_set: Configure the data format for a specific channel. + * @data_source_set: Configure the data source for a specific channel. + * @set_sample_rate: Configure the sampling rate for a specific channel. * @request_buffer: Request an IIO buffer. * @free_buffer: Free an IIO buffer. + * @extend_chan_spec: Extend an IIO channel. + * @ext_info_set: Extended info setter. + * @ext_info_get: Extended info getter. **/ struct iio_backend_ops { int (*enable)(struct iio_backend *back); @@ -45,10 +71,21 @@ 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); + int (*set_sample_rate)(struct iio_backend *back, unsigned int chan, + u64 sample_rate); 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 (*extend_chan_spec)(struct iio_backend *back, + struct iio_chan_spec *chan); + int (*ext_info_set)(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len); + int (*ext_info_get)(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, char *buf); }; int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan); @@ -56,10 +93,22 @@ 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 iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, + u64 sample_rate); int devm_iio_backend_request_buffer(struct device *dev, struct iio_backend *back, struct iio_dev *indio_dev); +ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len); +ssize_t iio_backend_ext_info_get(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf); +int iio_backend_extend_chan_spec(struct iio_dev *indio_dev, + struct iio_backend *back, + struct iio_chan_spec *chan); 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 Thu Mar 28 13:22:33 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: 13608531 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 E0EF281219; Thu, 28 Mar 2024 13:22:31 +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=1711632152; cv=none; b=ZL4zYUV8suynqTZih+t6kUwppKneqJgkB+JRhjVeMPsCja5+umoWOiAQJIHB9itStbBC2HD8sHX9Z23fuINfPjI6ddviVJ0Q2qRDBdo4a5GlBpWTkXZ/hENASnQi0VyHl9MkpAKqe/xi5F4McdegNiAhNKH2WnZ7VkKK+Fp5E2c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632152; c=relaxed/simple; bh=w8AvKUMhWLvQ2m/XQIuTZljlAxdNMEaYdX28L42CwEU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jTW5dlM8ixTG9wVLtjS8RRMiznPYRwz56WL1blaH6/wuvwXj8SEyoWc4S1MudFA+S3zJEQjNA+d9ldnuDiukaygX43MB0M1kUPglahC4UcIIrdlF6cI/5s6S2DjXxqwUxmw7UQUCRcyQMYBC1GkxaHze2rlPqcJo2ftyTZvKofk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Uqz5rlUM; 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="Uqz5rlUM" Received: by smtp.kernel.org (Postfix) with ESMTPS id A0463C43394; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=w8AvKUMhWLvQ2m/XQIuTZljlAxdNMEaYdX28L42CwEU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Uqz5rlUMq7nn7rfHUHFrinTJH8R+66nbUJp1DJkFrWhwHH4PQ5/NJu/wJ+R1QVZjX p7tq36hLSApnIy2yKVDiFOYxS5bjYrmaewMY2IQmr3XhymJPqH7cxdE+CA68iAl71O S8ru3BcxoOQqLTJ8SarFa9cv8eUg1rVywx7luIRyU8NOhMtD7/9kXQQFgPjtsMUCIT sQXQhtgjUtnHAts9l/1RTHpC1t/wBPejFKfY59/ztHHPgUk+tr3gDXtaTEZinN9b9p PAGhoGhuWqZy8I0OaQRqk2hOS3OXTJdlqNG/gA8HVY13NBCir++to96Fjk+l3RnlhE BCBV4HFlKyCng== 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 97BAACD1288; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:33 +0100 Subject: [PATCH 09/10] iio: 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: <20240328-iio-backend-axi-dac-v1-9-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=21005; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=DKM/JwU90qqED48pzzJk0k9o2FS7LkIH1rSvQb9Do50=; b=8LPhwdf4bZ469er5Xcb6VzbUdR5MyQMOQUO9a45kkW8ptJRyXkw2dEq8GSIIvCipd/pcIrQ51 xNDeDhbziEODkpMs2jOtG4SU/SaROVCHIMSaDTMOng1w4FBrNnTKagV 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: nuno.sa@analog.com From: Nuno Sa Support 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). Typically (for such devices) SPI will be used for configuration only, while this IP core handles the streaming of data into memory via DMA. Signed-off-by: Nuno Sa --- MAINTAINERS | 1 + drivers/iio/dac/Kconfig | 21 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/adi-axi-dac.c | 644 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 667 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 76e872e320d7..505f28dc6da6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1413,6 +1413,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml +F: drivers/iio/dac/adi-axi-dac.c ANALOG DEVICES INC DMA DRIVERS M: Lars-Peter Clausen diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 34eb40bb9529..7c0a8caa9a34 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -131,6 +131,27 @@ 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 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 55bf89739d14..6bcaa65434b2 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_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..0022ecb4e4bb --- /dev/null +++ b/drivers/iio/dac/adi-axi-dac.c @@ -0,0 +1,644 @@ +// 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 + +#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_DDS_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_CNTRL_2 0x0048 +#define ADI_DAC_R1_MODE BIT(4) +#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) (0x0408 + (c) * 0x40) +#define AXI_DAC_SCALE_SIGN BIT(15) +#define AXI_DAC_SCALE_INT BIT(14) +#define AXI_DAC_SCALE GENMASK(14, 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 to protect multiple accesses to the device registers and global + * data/variables. + */ + struct mutex lock; + u64 dac_clk; + u32 reg_config; + bool int_tone; +}; + +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 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); +} + +enum { + AXI_DAC_FREQ_TONE_1, + AXI_DAC_FREQ_TONE_2, + AXI_DAC_SCALE_TONE_1, + AXI_DAC_SCALE_TONE_2, + AXI_DAC_PHASE_TONE_1, + AXI_DAC_PHASE_TONE_2, +}; + +static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan, + unsigned int tone, unsigned int *freq) +{ + u32 reg, raw; + int ret; + + if (!st->dac_clk) { + dev_err(st->dev, "Sampling rate is 0...\n"); + return -EINVAL; + } + + if (tone == AXI_DAC_FREQ_TONE_1) + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan); + else + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan); + + ret = regmap_read(st->regmap, reg, &raw); + if (ret) + return ret; + + raw = FIELD_GET(AXI_DAC_FREQUENCY, raw); + *freq = DIV_ROUND_CLOSEST_ULL(raw * st->dac_clk, BIT(16)); + + return 0; +} + +static int axi_dac_frequency_get(struct axi_dac_state *st, + const struct iio_chan_spec *chan, char *buf, + unsigned int tone) +{ + unsigned int freq; + int ret; + + scoped_guard(mutex, &st->lock) { + ret = __axi_dac_frequency_get(st, chan->channel, tone, &freq); + if (ret) + return ret; + } + + return sysfs_emit(buf, "%u\n", freq); +} + +static int axi_dac_scale_get(struct axi_dac_state *st, + const struct iio_chan_spec *chan, char *buf, + unsigned int tone) +{ + unsigned int scale, sign; + int ret, vals[2]; + u32 reg, raw; + + if (tone == AXI_DAC_SCALE_TONE_1) + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + + ret = regmap_read(st->regmap, reg, &raw); + if (ret) + return ret; + + sign = FIELD_GET(AXI_DAC_SCALE_SIGN, raw); + raw = FIELD_GET(AXI_DAC_SCALE, raw); + scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA, AXI_DAC_SCALE_INT); + + vals[0] = scale / MEGA; + vals[1] = scale % MEGA; + + if (sign) { + vals[0] *= -1; + if (!vals[0]) + vals[1] *= -1; + } + + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(vals), + vals); +} + +static int axi_dac_phase_get(struct axi_dac_state *st, + const struct iio_chan_spec *chan, char *buf, + unsigned int tone) +{ + u32 reg, raw, phase; + int ret, vals[2]; + + if (tone == AXI_DAC_PHASE_TONE_1) + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + + ret = regmap_read(st->regmap, reg, &raw); + if (ret) + return ret; + + raw = FIELD_GET(AXI_DAC_PHASE, raw); + phase = DIV_ROUND_CLOSEST_ULL((u64)raw * AXI_DAC_2_PI_MEGA, U16_MAX); + + vals[0] = phase / MEGA; + vals[1] = phase % MEGA; + + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(vals), + vals); +} + +static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan, + u64 sample_rate, unsigned int freq, + unsigned int tone) +{ + u32 reg; + u16 raw; + int ret; + + if (!sample_rate || freq > sample_rate / 2) { + dev_err(st->dev, "Invalid frequency(%u) dac_clk(%llu)\n", + freq, sample_rate); + return -EINVAL; + } + + if (tone == AXI_DAC_FREQ_TONE_1) + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan); + else + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan); + + raw = DIV64_U64_ROUND_CLOSEST((u64)freq * BIT(16), sample_rate); + + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_FREQUENCY, raw); + if (ret) + return ret; + + /* synchronize channels */ + return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); +} + +static int axi_dac_frequency_set(struct axi_dac_state *st, + const struct iio_chan_spec *chan, + const char *buf, size_t len, unsigned int tone) +{ + unsigned int freq; + int ret; + + ret = kstrtou32(buf, 10, &freq); + if (ret) + return ret; + + guard(mutex)(&st->lock); + ret = __axi_dac_frequency_set(st, chan->channel, st->dac_clk, freq, + tone); + if (ret) + return ret; + + return len; +} + +static int axi_dac_scale_set(struct axi_dac_state *st, + const struct iio_chan_spec *chan, + const char *buf, size_t len, unsigned int tone) +{ + int integer, frac, scale; + u32 raw = 0, reg; + int ret; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); + if (ret) + return ret; + + scale = integer * MEGA + frac; + if (scale <= -2 * (int)MEGA || scale >= 2 * (int)MEGA) + return -EINVAL; + + /* format is 1.1.14 (sign, integer and fractional bits) */ + if (scale < 0) { + raw = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1); + scale *= -1; + } + + raw |= div_u64((u64)scale * AXI_DAC_SCALE_INT, MEGA); + + if (tone == AXI_DAC_SCALE_TONE_1) + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + + guard(mutex)(&st->lock); + ret = regmap_write(st->regmap, reg, raw); + if (ret) + return ret; + + /* synchronize channels */ + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + if (ret) + return ret; + + return len; +} + +static int axi_dac_phase_set(struct axi_dac_state *st, + const struct iio_chan_spec *chan, + const char *buf, size_t len, unsigned int tone) +{ + int integer, frac, phase; + u32 raw, reg; + int ret; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); + if (ret) + return ret; + + phase = integer * MEGA + frac; + if (phase < 0 || phase > AXI_DAC_2_PI_MEGA) + return -EINVAL; + + raw = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA); + + if (tone == AXI_DAC_PHASE_TONE_1) + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + + guard(mutex)(&st->lock); + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE, + FIELD_PREP(AXI_DAC_PHASE, raw)); + if (ret) + return ret; + + /* synchronize channels */ + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + if (ret) + return ret; + + return len; +} + +static int axi_dac_ext_info_set(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (private) { + case AXI_DAC_FREQ_TONE_1: + case AXI_DAC_FREQ_TONE_2: + return axi_dac_frequency_set(st, chan, buf, len, private); + case AXI_DAC_SCALE_TONE_1: + case AXI_DAC_SCALE_TONE_2: + return axi_dac_scale_set(st, chan, buf, len, private); + case AXI_DAC_PHASE_TONE_1: + case AXI_DAC_PHASE_TONE_2: + return axi_dac_phase_set(st, chan, buf, len, private); + default: + return -EOPNOTSUPP; + } +} + +static int axi_dac_ext_info_get(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (private) { + case AXI_DAC_FREQ_TONE_1: + case AXI_DAC_FREQ_TONE_2: + return axi_dac_frequency_get(st, chan, buf, private); + case AXI_DAC_SCALE_TONE_1: + case AXI_DAC_SCALE_TONE_2: + return axi_dac_scale_get(st, chan, buf, private); + case AXI_DAC_PHASE_TONE_1: + case AXI_DAC_PHASE_TONE_2: + return axi_dac_phase_get(st, chan, buf, private); + default: + return -EOPNOTSUPP; + } +} + +static const struct iio_chan_spec_ext_info axi_dac_ext_info[] = { + IIO_BACKEND_EX_INFO("frequency0", IIO_SEPARATE, AXI_DAC_FREQ_TONE_1), + IIO_BACKEND_EX_INFO("frequency1", IIO_SEPARATE, AXI_DAC_FREQ_TONE_2), + IIO_BACKEND_EX_INFO("scale0", IIO_SEPARATE, AXI_DAC_SCALE_TONE_1), + IIO_BACKEND_EX_INFO("scale1", IIO_SEPARATE, AXI_DAC_SCALE_TONE_2), + IIO_BACKEND_EX_INFO("phase0", IIO_SEPARATE, AXI_DAC_PHASE_TONE_1), + IIO_BACKEND_EX_INFO("phase1", IIO_SEPARATE, AXI_DAC_PHASE_TONE_2), + {} +}; + +static int axi_dac_extend_chan(struct iio_backend *back, + struct iio_chan_spec *chan) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + if (chan->type != IIO_ALTVOLTAGE) + return -EINVAL; + if (st->reg_config & AXI_DDS_DISABLE) + /* nothing to extend */ + return 0; + + chan->ext_info = axi_dac_ext_info; + + return 0; +} + +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 int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan, + u64 sample_rate) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + unsigned int freq; + int ret, tone; + + if (!sample_rate) + return -EINVAL; + if (st->reg_config & AXI_DDS_DISABLE) + /* nothing to care if DDS is disabled */ + return 0; + + guard(mutex)(&st->lock); + /* + * If dac_clk is 0 then this must be the first time we're being notified + * about the interface sample rate. Hence, just update our internal + * variable and bail... If it's not 0, then we get the current DDS + * frequency (for the old rate) and update the registers for the new + * sample rate. + */ + if (!st->dac_clk) { + st->dac_clk = sample_rate; + return 0; + } + + for (tone = 0; tone <= AXI_DAC_FREQ_TONE_2; tone++) { + ret = __axi_dac_frequency_get(st, chan, tone, &freq); + if (ret) + return ret; + + ret = __axi_dac_frequency_set(st, chan, sample_rate, tone, freq); + if (ret) + return ret; + } + + st->dac_clk = sample_rate; + + return 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, + .extend_chan_spec = axi_dac_extend_chan, + .ext_info_set = axi_dac_ext_info_set, + .ext_info_get = axi_dac_ext_info_get, + .data_source_set = axi_dac_data_source_set, + .set_sample_rate = axi_dac_set_sample_rate, +}; + +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; + + /* + * In some designs, setting the R1_MODE bit to 0 (which is the default + * value) causes all channels of the frontend to be routed to the same + * DMA (so they are sampled together). This is for things like + * Multiple-Input and Multiple-Output (MIMO). As most of the times we + * want independent channels let's override the core's default value and + * set the R1_MODE bit. + */ + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2, ADI_DAC_R1_MODE); + 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"); +MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); +MODULE_IMPORT_NS(IIO_BACKEND); From patchwork Thu Mar 28 13:22:34 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: 13608534 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 D662A80BEC; Thu, 28 Mar 2024 13:22:31 +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=1711632151; cv=none; b=p+BW/gKmZIBViwkN5pfBC1txaHwRgjizluix7Uwx+Gc9IGbF3sZ7qVvOGwq3vA4kTVFJRXjWX1GPr3+MBekFIbGCWrwZubp9R8EUAuECb/5QiDZoHcsOOz0PP6GS5RWRyAVz2CSl5hn7ztfZMSKz4yVjz/e1rOlKuMg+TbwjPKg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711632151; c=relaxed/simple; bh=LF19WaaztjHdCc6OVmbu8EJvVviIRgJSVfjtU2nVnzI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nFRletwBktxnyPNYylreW/NTfUvrHzrYQ2TFDUCECGzHzGRnx/qQDW+LbyzwPPStogQUrqziq8OagE8QT/0AfkPb9H0gX34l5AG1s2Pki4k2DUU1QeRj2sX5e7t/4P2jjVhw/ZxyF6zRpS6+aQxH/3WgvRRcRVy+BY2m0ZjkXuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FdwChKeP; 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="FdwChKeP" Received: by smtp.kernel.org (Postfix) with ESMTPS id B4F35C43390; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1711632151; bh=LF19WaaztjHdCc6OVmbu8EJvVviIRgJSVfjtU2nVnzI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=FdwChKePih8yPF8GCWKr8mh1/oR8gZTQizWKLvbNXprQLvrXd4/LxqPebE/bya/8Z FnPPUI0TnYmYQqWALVCVp19zyhbko3Cwsxhidv4H8udE46qaMxN1ZnSIODODjX5NU+ I/zZ880kUOhpAT/F8ReECLKLScuU5bzAhf1arFe7okWED15qV3+o9EvV61Tr9GU+4p KBLJZLLAFUkUBAlrXUJpDmAkdIORywJ3Ie/X7b0EXMSBYDaCWyJ5BmwdRnQZwIIiTk v7UbKiKwuGEnHD7/n+Sdpxvzj23/LM5iZqDa68jytChYsOLdWbDPfZZn3hE+xozLt1 DyQBCMfz9hryQ== 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 A96F5C54E67; Thu, 28 Mar 2024 13:22:31 +0000 (UTC) From: Nuno Sa via B4 Relay Date: Thu, 28 Mar 2024 14:22:34 +0100 Subject: [PATCH 10/10] iio: dac: support the ad9739a RF DAC Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240328-iio-backend-axi-dac-v1-10-afc808b3fde3@analog.com> References: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> In-Reply-To: <20240328-iio-backend-axi-dac-v1-0-afc808b3fde3@analog.com> To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org Cc: Dragos Bogdan , Jonathan Cameron , Lars-Peter Clausen , Michael Hennerich , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Nuno Sa X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1711632149; l=16736; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=UHJOHHEi0BGVi14Ir1h0p3C6TAALF+GQOiEx2J3ylDQ=; b=CjDNLNKLdSgFD1equAvlMWpxTVARFmu5xlV61v0WxfJTXIIIHBHRQTwI5DblZx22sJPKR3vHV 7+7hnqlSafbCx6s2mVYrQlnIBdHhoxnpx5hrdPtfd9foXcZwxrwlIx1 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: nuno.sa@analog.com From: Nuno Sa The AD9739A is a 14-bit, 2.5 GSPS high performance RF DACs that are capable of synthesizing wideband signals from dc up to 3 GHz. A dual-port, source synchronous, LVDS interface simplifies the digital interface with existing FGPA/ASIC technology. 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. Co-developed-by: Dragos Bogdan Signed-off-by: Dragos Bogdan Signed-off-by: Nuno Sa --- Documentation/ABI/testing/sysfs-bus-iio-ad9739a | 17 + MAINTAINERS | 1 + drivers/iio/dac/Kconfig | 16 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad9739a.c | 445 ++++++++++++++++++++++++ 5 files changed, 480 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-ad9739a b/Documentation/ABI/testing/sysfs-bus-iio-ad9739a new file mode 100644 index 000000000000..8a8a5cd10386 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-ad9739a @@ -0,0 +1,17 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_operating_mode +KernelVersion: 6.9 +Contact: linux-iio@vger.kernel.org +Description: + Dac operating mode. One of the following modes can be selected: + * normal: This is DAC normal mode. + * mixed-mode: In this mode the output is effectively chopped at the + DAC sample rate. This has the effect of reducing the + power of the fundamental signal while increasing the + power of the images centered around the DAC sample rate, + thus improving the output power of these images. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_operating_mode_available +KernelVersion: 6.9 +Contact: linux-iio@vger.kernel.org +Description: + Available operating modes. diff --git a/MAINTAINERS b/MAINTAINERS index 505f28dc6da6..8ad79cf70552 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1241,6 +1241,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml +F: drivers/iio/dac/ad9739a.c ANALOG DEVICES INC ADA4250 DRIVER M: Antoniu Miclaus diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 7c0a8caa9a34..ee0d9798d8b4 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 ADI_AXI_DAC tristate "Analog Devices Generic AXI DAC IP core driver" select IIO_BUFFER diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 6bcaa65434b2..8432a81a19dc 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_ADI_AXI_DAC) += adi-axi-dac.o obj-$(CONFIG_CIO_DAC) += cio-dac.o obj-$(CONFIG_DPOT_DAC) += dpot-dac.o diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c new file mode 100644 index 000000000000..46431fa345a5 --- /dev/null +++ b/drivers/iio/dac/ad9739a.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD9739a SPI DAC driver + * + * Copyright 2015-2024 Analog Devices Inc. + */ +#include +#include +#include +#include +#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_FSC_1 0x06 +#define AD9739A_REG_FSC_2 0x07 +#define AD9739A_FSC_MSB GENMASK(1, 0) +#define AD9739A_REG_DEC_CNT 0x8 +#define AD9739A_DAC_DEC GENMASK(1, 0) +#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_FSC_MIN 8700 +#define AD9739A_FSC_MAX 31700 +#define AD9739A_FSC_RANGE (AD9739A_FSC_MAX - AD9739A_FSC_MIN + 1) + +#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; +}; + +enum { + AD9739A_NORMAL_MODE, + AD9739A_MIXED_MODE = 2, +}; + +static int ad9739a_oper_mode_get(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + u32 mode; + int ret; + + ret = regmap_read(st->regmap, AD9739A_REG_DEC_CNT, &mode); + if (ret) + return ret; + + mode = FIELD_GET(AD9739A_DAC_DEC, mode); + /* sanity check we get valid values from the HW */ + if (mode != AD9739A_NORMAL_MODE && mode != AD9739A_MIXED_MODE) + return -EIO; + if (!mode) + return AD9739A_NORMAL_MODE; + + return AD9739A_MIXED_MODE - 1; +} + +static int ad9739a_oper_mode_set(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, u32 mode) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + if (mode == AD9739A_MIXED_MODE - 1) + mode = AD9739A_MIXED_MODE; + + return regmap_update_bits(st->regmap, AD9739A_REG_DEC_CNT, + AD9739A_DAC_DEC, mode); +} + +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; + } +} + +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, fsc; + u32 fsc_raw; + 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 and 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"); + + ret = device_property_read_u32(dev, "adi,full-scale-microamp", &fsc); + if (ret && ret == -EINVAL) + return 0; + if (ret) + return ret; + if (!in_range(fsc, AD9739A_FSC_MIN, AD9739A_FSC_RANGE)) + return dev_err_probe(dev, -EINVAL, + "Invalid full scale current(%u) [%u %u]\n", + fsc, AD9739A_FSC_MIN, AD9739A_FSC_MAX); + /* + * IOUTFS is given by + * Ioutfs = 0.0226 * FSC + 8.58 + * and is given in mA. Hence we'll have to multiply by 10 * MILLI in + * order to get rid of the fractional. + */ + fsc_raw = DIV_ROUND_CLOSEST(fsc * 10 - 85800, 226); + + ret = regmap_write(st->regmap, AD9739A_REG_FSC_1, fsc_raw & 0xff); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, AD9739A_REG_FSC_1, + AD9739A_FSC_MSB, fsc_raw >> 8); +} + +static const char * const ad9739a_modes_avail[] = { "normal", "mixed-mode" }; + +static const struct iio_enum ad9739a_modes = { + .items = ad9739a_modes_avail, + .num_items = ARRAY_SIZE(ad9739a_modes_avail), + .get = ad9739a_oper_mode_get, + .set = ad9739a_oper_mode_set, +}; + +static const struct iio_chan_spec_ext_info ad9739a_ext_info[] = { + IIO_ENUM_AVAILABLE("operating_mode", IIO_SEPARATE, &ad9739a_modes), + IIO_ENUM("operating_mode", IIO_SEPARATE, &ad9739a_modes), +}; + +static struct iio_chan_spec ad9739a_channels[] = { + { + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .output = 1, + .scan_index = -1, + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .output = 1, + .ext_info = ad9739a_ext_info, + .scan_type = { + .sign = 's', + .storagebits = 16, + .realbits = 16, + }, + } +}; + +static const struct iio_info ad9739a_info = { + .read_raw = ad9739a_read_raw, +}; + +static const struct iio_buffer_setup_ops ad9739a_buffer_setup_ops = { + .preenable = &ad9739a_buffer_preenable, + .postdisable = &ad9739a_buffer_postdisable, +}; + +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, +}; + +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 = iio_backend_extend_chan_spec(indio_dev, st->back, + &ad9739a_channels[0]); + if (ret) + return ret; + + ret = iio_backend_set_sampling_freq(st->back, 0, st->sample_rate); + 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_channels; + indio_dev->num_channels = ARRAY_SIZE(ad9739a_channels); + 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"); +MODULE_IMPORT_NS(IIO_BACKEND);