linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Lechner <dlechner@baylibre.com>
To: "Mark Brown" <broonie@kernel.org>,
	"Jonathan Cameron" <jic23@kernel.org>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Michael Hennerich" <michael.hennerich@analog.com>,
	"Nuno Sá" <nuno.sa@analog.com>,
	"Frank Rowand" <frowand.list@gmail.com>
Cc: "David Lechner" <dlechner@baylibre.com>,
	"Thierry Reding" <thierry.reding@gmail.com>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Jonathan Corbet" <corbet@lwn.net>,
	linux-spi@vger.kernel.org, linux-iio@vger.kernel.org,
	devicetree@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 12/13] iio: offload: add new PWM triggered DMA buffer driver
Date: Wed, 10 Jan 2024 13:49:53 -0600	[thread overview]
Message-ID: <20240109-axi-spi-engine-series-3-v1-12-e42c6a986580@baylibre.com> (raw)
In-Reply-To: <20240109-axi-spi-engine-series-3-v1-0-e42c6a986580@baylibre.com>

This adds a new driver for handling SPI offloading using a PWM as the
trigger and DMA for the received data. This will be used by ADCs in
conjunction with SPI controllers with offloading support to be able
to sample at high rates without CPU intervention.

Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 drivers/iio/Kconfig                                |   1 +
 drivers/iio/Makefile                               |   1 +
 .../iio/buffer/industrialio-hw-triggered-buffer.c  |   1 +
 drivers/iio/offload/Kconfig                        |  21 ++
 drivers/iio/offload/Makefile                       |   2 +
 drivers/iio/offload/iio-pwm-triggered-dma-buffer.c | 212 +++++++++++++++++++++
 6 files changed, 238 insertions(+)

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 52eb46ef84c1..56738282d82f 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -90,6 +90,7 @@ source "drivers/iio/imu/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/magnetometer/Kconfig"
 source "drivers/iio/multiplexer/Kconfig"
+source "drivers/iio/offload/Kconfig"
 source "drivers/iio/orientation/Kconfig"
 source "drivers/iio/test/Kconfig"
 if IIO_TRIGGER
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 9622347a1c1b..20acf5e1a4a7 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -34,6 +34,7 @@ obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
 obj-y += multiplexer/
+obj-y += offload/
 obj-y += orientation/
 obj-y += position/
 obj-y += potentiometer/
diff --git a/drivers/iio/buffer/industrialio-hw-triggered-buffer.c b/drivers/iio/buffer/industrialio-hw-triggered-buffer.c
index 7a8a71066b0e..a2fae6059616 100644
--- a/drivers/iio/buffer/industrialio-hw-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-hw-triggered-buffer.c
@@ -86,6 +86,7 @@ static int iio_hw_trigger_buffer_probe(struct auxiliary_device *adev,
 }
 
 static const struct auxiliary_device_id iio_hw_trigger_buffer_id_table[] = {
+	{ .name = "pwm-triggered-dma-buffer.triggered-buffer" },
 	{ }
 };
 MODULE_DEVICE_TABLE(auxiliary, iio_hw_trigger_buffer_id_table);
diff --git a/drivers/iio/offload/Kconfig b/drivers/iio/offload/Kconfig
new file mode 100644
index 000000000000..760c0cfe0e9c
--- /dev/null
+++ b/drivers/iio/offload/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# SPI offload handlers for Industrial I/O
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "SPI offload handlers"
+
+config IIO_PWM_TRIGGERED_DMA_BUFFER
+	tristate "PWM trigger and DMA buffer connected to SPI offload"
+	select AUXILIARY_BUS
+	select IIO_BUFFER_DMAENGINE
+	help
+	  Provides a periodic hardware trigger via a PWM connected to the
+	  trigger input of a SPI offload and a hardware buffer implemented
+	  via DMA connected to the data output stream the a SPI offload.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called "iio-pwm-triggered-dma-buffer".
+
+endmenu
diff --git a/drivers/iio/offload/Makefile b/drivers/iio/offload/Makefile
new file mode 100644
index 000000000000..7300ce82f066
--- /dev/null
+++ b/drivers/iio/offload/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_IIO_PWM_TRIGGERED_DMA_BUFFER) := iio-pwm-triggered-dma-buffer.o
diff --git a/drivers/iio/offload/iio-pwm-triggered-dma-buffer.c b/drivers/iio/offload/iio-pwm-triggered-dma-buffer.c
new file mode 100644
index 000000000000..970ea82316f6
--- /dev/null
+++ b/drivers/iio/offload/iio-pwm-triggered-dma-buffer.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Platform driver for a PWM trigger and DMA buffer connected to a SPI
+ * controller offload instance implementing the iio-hw-triggered-buffer
+ * interface.
+ *
+ * Copyright (C) 2023 Analog Devices, Inc.
+ * Copyright (C) 2023 BayLibre, SAS
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/pwm.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/hw_triggered_buffer_impl.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/sysfs.h>
+
+struct iio_pwm_triggered_dma_buffer {
+	struct iio_hw_triggered_buffer_device hw;
+	struct pwm_device *pwm;
+};
+
+static const struct iio_trigger_ops iio_pwm_triggered_dma_buffer_ops;
+
+static int iio_pwm_triggered_dma_buffer_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_pwm_triggered_dma_buffer *st = iio_trigger_get_drvdata(trig);
+
+	if (state)
+		return pwm_enable(st->pwm);
+
+	pwm_disable(st->pwm);
+
+	return 0;
+}
+
+static int iio_pwm_triggered_dma_buffer_validate_device(struct iio_trigger *trig,
+							struct iio_dev *indio_dev)
+{
+	/* Don't allow assigning trigger via sysfs. */
+	return -EINVAL;
+}
+
+static const struct iio_trigger_ops iio_pwm_triggered_dma_buffer_ops = {
+	.set_trigger_state = iio_pwm_triggered_dma_buffer_set_state,
+	.validate_device = iio_pwm_triggered_dma_buffer_validate_device,
+};
+
+static u32 axi_spi_engine_offload_pwm_trigger_get_rate(struct iio_trigger *trig)
+{
+	struct iio_pwm_triggered_dma_buffer *st = iio_trigger_get_drvdata(trig);
+	u64 period_ns = pwm_get_period(st->pwm);
+
+	if (period_ns)
+		return DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, period_ns);
+
+	return 0;
+}
+
+static int
+axi_spi_engine_offload_set_samp_freq(struct iio_pwm_triggered_dma_buffer *st,
+				     u32 requested_hz)
+{
+	int period_ns;
+
+	if (requested_hz == 0)
+		return -EINVAL;
+
+	period_ns = DIV_ROUND_UP(NSEC_PER_SEC, requested_hz);
+
+	/*
+	 * FIXME: We really just need a clock, not a PWM. The current duty cycle
+	 * value is a hack to work around the edge vs. level offload trigger
+	 * issue in the ADI AXI SPI Engine firmware.
+	 */
+	return pwm_config(st->pwm, 10, period_ns);
+}
+
+static ssize_t sampling_frequency_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+
+	return sysfs_emit(buf, "%u\n",
+			  axi_spi_engine_offload_pwm_trigger_get_rate(trig));
+}
+
+static ssize_t sampling_frequency_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_pwm_triggered_dma_buffer *st = iio_trigger_get_drvdata(trig);
+	int ret;
+	u32 val;
+
+	ret = kstrtou32(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = axi_spi_engine_offload_set_samp_freq(st, val);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static DEVICE_ATTR_RW(sampling_frequency);
+
+static struct attribute *iio_pwm_triggered_dma_buffer_attrs[] = {
+	&dev_attr_sampling_frequency.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(iio_pwm_triggered_dma_buffer);
+
+static void iio_pwm_triggered_dma_buffer_adev_release(struct device *dev)
+{
+}
+
+static void iio_pwm_triggered_dma_buffer_unregister_adev(void *adev)
+{
+	auxiliary_device_delete(adev);
+	auxiliary_device_uninit(adev);
+}
+
+static int iio_pwm_triggered_dma_buffer_probe(struct platform_device *pdev)
+{
+	struct iio_pwm_triggered_dma_buffer *st;
+	struct auxiliary_device *adev;
+	int ret;
+
+	st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	st->pwm = devm_pwm_get(&pdev->dev, NULL);
+	if (IS_ERR(st->pwm))
+		return dev_err_probe(&pdev->dev, PTR_ERR(st->pwm),
+				     "failed to get PWM\n");
+
+	st->hw.buffer = devm_iio_dmaengine_buffer_alloc(&pdev->dev, "rx");
+	if (IS_ERR(st->hw.buffer))
+		return dev_err_probe(&pdev->dev, PTR_ERR(st->hw.buffer),
+				     "failed to allocate buffer\n");
+
+	st->hw.trig = devm_iio_trigger_alloc(&pdev->dev, "%s-%s-pwm-trigger",
+					     dev_name(pdev->dev.parent),
+					     dev_name(&pdev->dev));
+	if (!st->hw.trig)
+		return -ENOMEM;
+
+	st->hw.trig->ops = &iio_pwm_triggered_dma_buffer_ops;
+	st->hw.trig->dev.parent = &pdev->dev;
+	st->hw.trig->dev.groups = iio_pwm_triggered_dma_buffer_groups;
+	iio_trigger_set_drvdata(st->hw.trig, st);
+
+	/* start with a reasonable default value */
+	ret = axi_spi_engine_offload_set_samp_freq(st, 1000);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "failed to set sampling frequency\n");
+
+	ret = devm_iio_trigger_register(&pdev->dev, st->hw.trig);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "failed to register trigger\n");
+
+	adev = &st->hw.adev;
+	adev->name = "triggered-buffer";
+	adev->dev.parent = &pdev->dev;
+	adev->dev.release = iio_pwm_triggered_dma_buffer_adev_release;
+	adev->id = 0;
+
+	ret = auxiliary_device_init(adev);
+	if (ret)
+		return ret;
+
+	ret = auxiliary_device_add(adev);
+	if (ret) {
+		auxiliary_device_uninit(adev);
+		return ret;
+	}
+
+	return devm_add_action_or_reset(&pdev->dev,
+			iio_pwm_triggered_dma_buffer_unregister_adev, adev);
+}
+
+static const struct of_device_id iio_pwm_triggered_dma_buffer_match_table[] = {
+	{ .compatible = "adi,spi-offload-pwm-trigger-dma-buffer" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, iio_pwm_triggered_dma_buffer_match_table);
+
+static struct platform_driver iio_pwm_triggered_dma_buffer_driver = {
+	.probe = iio_pwm_triggered_dma_buffer_probe,
+	.driver = {
+		.name = "iio-pwm-triggered-dma-buffer",
+		.of_match_table = iio_pwm_triggered_dma_buffer_match_table,
+	},
+};
+module_platform_driver(iio_pwm_triggered_dma_buffer_driver);
+
+MODULE_AUTHOR("David Lechner <dlechner@baylibre.com>");
+MODULE_DESCRIPTION("AXI SPI Engine Offload PWM Trigger");
+MODULE_LICENSE("GPL");

-- 
2.43.0


  parent reply	other threads:[~2024-01-10 19:51 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-10 19:49 [PATCH 00/13] spi: axi-spi-engine: add offload support David Lechner
2024-01-10 19:49 ` [PATCH 01/13] spi: add core support for controllers with offload capabilities David Lechner
2024-01-10 21:36   ` Mark Brown
2024-01-11 20:54     ` David Lechner
2024-01-11 21:32       ` David Lechner
2024-01-11 21:49         ` Mark Brown
2024-01-12  9:03           ` David Jander
2024-01-12 20:09         ` David Lechner
2024-03-04 23:21     ` David Lechner
2024-03-05 18:50       ` Mark Brown
2024-03-09 17:54       ` Jonathan Cameron
2024-01-11  8:49   ` Nuno Sá
2024-01-11 13:33     ` Mark Brown
2024-01-11 14:11       ` Nuno Sá
2024-01-11 15:41         ` Mark Brown
2024-01-12  7:26           ` Nuno Sá
2024-01-10 19:49 ` [PATCH 02/13] scripts: dtc: checks: don't warn on SPI non-peripheral child nodes David Lechner
2024-01-11 22:03   ` Rob Herring
2024-01-10 19:49 ` [PATCH 03/13] spi: do not attempt to register DT nodes without @ in name David Lechner
2024-01-10 21:37   ` Mark Brown
2024-01-10 19:49 ` [PATCH 04/13] spi: dt-bindings: adi,axi-spi-engine: add offload bindings David Lechner
2024-01-10 23:14   ` Rob Herring
2024-01-11  0:06     ` David Lechner
2024-01-11  9:14       ` Nuno Sá
2024-01-11  9:07     ` Nuno Sá
2024-01-10 19:49 ` [PATCH 05/13] spi: axi-spi-engine: add SPI offload support David Lechner
2024-01-10 21:39   ` Mark Brown
2024-01-10 22:31     ` David Lechner
2024-01-11 13:00       ` Mark Brown
2024-01-11 17:57         ` David Lechner
2024-01-10 19:49 ` [PATCH 06/13] iio: buffer: add hardware triggered buffer support David Lechner
2024-01-12 12:37   ` Jonathan Cameron
2024-01-12 15:42     ` David Lechner
2024-01-12 16:50       ` Nuno Sá
2024-01-10 19:49 ` [PATCH 07/13] iio: buffer: dmaengine: add INDIO_HW_BUFFER_TRIGGERED flag David Lechner
2024-01-10 19:49 ` [PATCH 08/13] iio: buffer: add new hardware triggered buffer driver David Lechner
2024-01-11  9:24   ` Nuno Sá
2024-01-10 19:49 ` [PATCH 09/13] bus: auxiliary: increase AUXILIARY_NAME_SIZE David Lechner
2024-01-10 19:49 ` [PATCH 10/13] iio: buffer: dmaengine: export devm_iio_dmaengine_buffer_alloc() David Lechner
2024-01-12 12:37   ` Jonathan Cameron
2024-01-12 14:55     ` David Lechner
2024-01-10 19:49 ` [PATCH 11/13] dt-bindings: iio: offload: add binding for PWM/DMA triggered buffer David Lechner
2024-01-10 21:25   ` Rob Herring
2024-01-10 22:56   ` Rob Herring
2024-01-10 19:49 ` David Lechner [this message]
2024-01-11  9:31   ` [PATCH 12/13] iio: offload: add new PWM triggered DMA buffer driver Nuno Sá
2024-01-11 14:59   ` Nuno Sá
2024-01-12 12:51     ` Jonathan Cameron
2024-01-12 13:19       ` Nuno Sá
2024-01-12 12:45   ` Jonathan Cameron
2024-01-10 19:49 ` [PATCH 13/13] iio: adc: ad7380: add SPI offload support David Lechner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240109-axi-spi-engine-series-3-v1-12-e42c6a986580@baylibre.com \
    --to=dlechner@baylibre.com \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=jic23@kernel.org \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=michael.hennerich@analog.com \
    --cc=nuno.sa@analog.com \
    --cc=robh+dt@kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).