Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2216875/?format=api
{ "id": 2216875, "url": "http://patchwork.ozlabs.org/api/patches/2216875/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/patch/20260327-ad4692-multichannel-sar-adc-driver-v5-3-11f789de47b8@analog.com/", "project": { "id": 38, "url": "http://patchwork.ozlabs.org/api/projects/38/?format=api", "name": "Linux PWM development", "link_name": "linux-pwm", "list_id": "linux-pwm.vger.kernel.org", "list_email": "linux-pwm@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260327-ad4692-multichannel-sar-adc-driver-v5-3-11f789de47b8@analog.com>", "list_archive_url": null, "date": "2026-03-27T11:07:59", "name": "[v5,3/4] iio: adc: ad4691: add triggered buffer support", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "0068af1391d6cf6e4bc20f8c663562eab988a022", "submitter": { "id": 92791, "url": "http://patchwork.ozlabs.org/api/people/92791/?format=api", "name": "Radu Sabau via B4 Relay", "email": "devnull+radu.sabau.analog.com@kernel.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-pwm/patch/20260327-ad4692-multichannel-sar-adc-driver-v5-3-11f789de47b8@analog.com/mbox/", "series": [ { "id": 497746, "url": "http://patchwork.ozlabs.org/api/series/497746/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/list/?series=497746", "date": "2026-03-27T11:07:56", "name": "iio: adc: ad4691: add driver for AD4691 multichannel SAR ADC family", "version": 5, "mbox": "http://patchwork.ozlabs.org/series/497746/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2216875/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2216875/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <linux-pwm+bounces-8386-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-pwm@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=nA4cgDwE;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-pwm+bounces-8386-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"nA4cgDwE\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201" ], "Received": [ "from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fhyn54cQ4z1y1x\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 27 Mar 2026 22:18:17 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id ED50030B899D\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 27 Mar 2026 11:08:54 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 9ECC83E9F85;\n\tFri, 27 Mar 2026 11:08:10 +0000 (UTC)", "from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 532F33E868E;\n\tFri, 27 Mar 2026 11:08:08 +0000 (UTC)", "by smtp.kernel.org (Postfix) with ESMTPS id 6835CC2BCB6;\n\tFri, 27 Mar 2026 11:08:07 +0000 (UTC)", "from aws-us-west-2-korg-lkml-1.web.codeaurora.org\n (localhost.localdomain [127.0.0.1])\n\tby smtp.lore.kernel.org (Postfix) with ESMTP id 5A3C110ED660;\n\tFri, 27 Mar 2026 11:08:07 +0000 (UTC)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774609688; cv=none;\n b=N1BbscPJbgzibihWqcgJQecdhgMJ/jYCllSgYANGwYrOAQQKEJPqeLc919I1RFtmTAHMULrv9kG4lGjel45LS7wBStOXodacqDqh29UYMeuYwWgwd91v0yvoaYw0J7aDJYR0SMRpjQ6W2JPjQuQprWU+/3QdFQxTrBriz3w2k5s=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774609688; c=relaxed/simple;\n\tbh=eAUEuxAI6BMChPW8ZNRevtIaxkcGV3eL5SV42cG5aiE=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:\n\t In-Reply-To:To:Cc;\n b=OTmWx89mbQZf2y7jDbkwQYJqvxykm1g2R34zsuoWjrsLTCORZAorVne3LB1AQwZfTiCgEcogFSHRxrUH6rsvfaA9NLsFYY3mIhEizatRjz/1yDRu51zeFWNyWyhu4yPmiK1OKFDNInXqbw3SUU10FaX6Tx16Knq32SYLaZNV1pQ=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=nA4cgDwE; arc=none smtp.client-ip=10.30.226.201", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1774609687;\n\tbh=eAUEuxAI6BMChPW8ZNRevtIaxkcGV3eL5SV42cG5aiE=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From;\n\tb=nA4cgDwEyEE7wrRRUv9lVPFdGpXcM2K4pNonDwylOlbkTNhZo+AX2z0J1eszSAQ0f\n\t YWG6Hn24DhCMXcwvPuW2N/1OC0QIOTobNlzkntDsNQMW1wrq38INbhcUH12/LVFKCD\n\t 3s/TTeILj2M00U9Alv7MOVQu/PoSRxIcm9hhXUVW7m/lJYWDtymwUiLhPOrTvYwUee\n\t uyoaQ6eAG4U1ofBk0Gaxmuu8d0x2EV3EJEDcmgT4ZYIIyjrfwOgnv16yZMVUJKtKhk\n\t BPXl/3lXXr+awvBaeU0ZIvhj31hL3O1gGrZDfArYg+WkUER5MwRaP6nc7rYPfRiGU6\n\t 1r6CW7vgOYqhg==", "From": "Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org>", "Date": "Fri, 27 Mar 2026 13:07:59 +0200", "Subject": "[PATCH v5 3/4] iio: adc: ad4691: add triggered buffer support", "Precedence": "bulk", "X-Mailing-List": "linux-pwm@vger.kernel.org", "List-Id": "<linux-pwm.vger.kernel.org>", "List-Subscribe": "<mailto:linux-pwm+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-pwm+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "8bit", "Message-Id": "\n <20260327-ad4692-multichannel-sar-adc-driver-v5-3-11f789de47b8@analog.com>", "References": "\n <20260327-ad4692-multichannel-sar-adc-driver-v5-0-11f789de47b8@analog.com>", "In-Reply-To": "\n <20260327-ad4692-multichannel-sar-adc-driver-v5-0-11f789de47b8@analog.com>", "To": "Lars-Peter Clausen <lars@metafoo.de>,\n Michael Hennerich <Michael.Hennerich@analog.com>,\n Jonathan Cameron <jic23@kernel.org>, David Lechner <dlechner@baylibre.com>,\n\t=?utf-8?q?Nuno_S=C3=A1?= <nuno.sa@analog.com>,\n Andy Shevchenko <andy@kernel.org>, Rob Herring <robh@kernel.org>,\n Krzysztof Kozlowski <krzk+dt@kernel.org>,\n Conor Dooley <conor+dt@kernel.org>,\n =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= <ukleinek@kernel.org>,\n Liam Girdwood <lgirdwood@gmail.com>, Mark Brown <broonie@kernel.org>,\n Linus Walleij <linusw@kernel.org>, Bartosz Golaszewski <brgl@kernel.org>,\n Philipp Zabel <p.zabel@pengutronix.de>, Jonathan Corbet <corbet@lwn.net>,\n Shuah Khan <skhan@linuxfoundation.org>", "Cc": "linux-iio@vger.kernel.org, devicetree@vger.kernel.org,\n linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,\n linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org,\n Radu Sabau <radu.sabau@analog.com>", "X-Mailer": "b4 0.14.3", "X-Developer-Signature": "v=1; a=ed25519-sha256; t=1774609685; l=26299;\n i=radu.sabau@analog.com; s=20260220; h=from:subject:message-id;\n bh=pxUrXjcP9Mj30KZrMMvsCz073pWQWLaZs1wPmK1vy8s=;\n b=hpDpop//q9LT0v1DTFRdLjS1/6H6SxmBMjJUlAbaVWOWF5BIsmu4TKnHvwkEzNeE1DNtu6Vm/\n rFSskVtf/biDse0NzmUuZz7+2p00kmkGxg/tHrNKYIqg9dGkvUfeMFm", "X-Developer-Key": "i=radu.sabau@analog.com; a=ed25519;\n pk=lDPQHgn9jTdt0vo58Na9lLxLaE2mb330if71Cn+EvFU=", "X-Endpoint-Received": "by B4 Relay for radu.sabau@analog.com/20260220 with\n auth_id=642", "X-Original-From": "Radu Sabau <radu.sabau@analog.com>", "Reply-To": "radu.sabau@analog.com" }, "content": "From: Radu Sabau <radu.sabau@analog.com>\n\nAdd buffered capture support using the IIO triggered buffer framework.\n\nCNV Burst Mode: the GP pin identified by interrupt-names in the device\ntree is configured as DATA_READY output. The IRQ handler stops\nconversions and fires the IIO trigger; the trigger handler executes a\npre-built SPI message that reads all active channels from the AVG_IN\naccumulator registers and then resets accumulator state and restarts\nconversions for the next cycle.\n\nManual Mode: CNV is tied to SPI CS so each transfer simultaneously\nreads the previous result and starts the next conversion (pipelined\nN+1 scheme). At preenable time a pre-built, optimised SPI message of\nN+1 transfers is constructed (N channel reads plus one NOOP to drain\nthe pipeline). The trigger handler executes the message in a single\nspi_sync() call and collects the results. An external trigger (e.g.\niio-trig-hrtimer) is required to drive the trigger at the desired\nsample rate.\n\nBoth modes share the same trigger handler and push a complete scan —\none u16 slot per channel at its scan_index position, followed by a\ntimestamp — to the IIO buffer via iio_push_to_buffers_with_ts().\n\nThe CNV Burst Mode sampling frequency (PWM period) is exposed as a\nbuffer-level attribute via IIO_DEVICE_ATTR.\n\nSigned-off-by: Radu Sabau <radu.sabau@analog.com>\n---\n drivers/iio/adc/Kconfig | 2 +\n drivers/iio/adc/ad4691.c | 616 ++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 612 insertions(+), 6 deletions(-)", "diff": "diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig\nindex 3685a03aa8dc..d498f16c0816 100644\n--- a/drivers/iio/adc/Kconfig\n+++ b/drivers/iio/adc/Kconfig\n@@ -142,6 +142,8 @@ config AD4170_4\n config AD4691\n \ttristate \"Analog Devices AD4691 Family ADC Driver\"\n \tdepends on SPI\n+\tselect IIO_BUFFER\n+\tselect IIO_TRIGGERED_BUFFER\n \tselect REGMAP\n \thelp\n \t Say yes here to build support for Analog Devices AD4691 Family MuxSAR\ndiff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c\nindex f930efdb9d8c..b5a7646b46ca 100644\n--- a/drivers/iio/adc/ad4691.c\n+++ b/drivers/iio/adc/ad4691.c\n@@ -4,14 +4,18 @@\n * Author: Radu Sabau <radu.sabau@analog.com>\n */\n #include <linux/bitfield.h>\n+#include <linux/bitmap.h>\n #include <linux/bitops.h>\n #include <linux/cleanup.h>\n #include <linux/delay.h>\n #include <linux/device.h>\n #include <linux/err.h>\n+#include <linux/interrupt.h>\n #include <linux/math.h>\n #include <linux/module.h>\n #include <linux/mod_devicetable.h>\n+#include <linux/property.h>\n+#include <linux/pwm.h>\n #include <linux/regmap.h>\n #include <linux/regulator/consumer.h>\n #include <linux/reset.h>\n@@ -19,7 +23,12 @@\n #include <linux/units.h>\n #include <linux/unaligned.h>\n \n+#include <linux/iio/buffer.h>\n #include <linux/iio/iio.h>\n+#include <linux/iio/sysfs.h>\n+#include <linux/iio/trigger.h>\n+#include <linux/iio/triggered_buffer.h>\n+#include <linux/iio/trigger_consumer.h>\n \n #define AD4691_VREF_uV_MIN\t\t\t2400000\n #define AD4691_VREF_uV_MAX\t\t\t5250000\n@@ -28,6 +37,8 @@\n #define AD4691_VREF_3P3_uV_MAX\t\t\t3750000\n #define AD4691_VREF_4P096_uV_MAX\t\t4500000\n \n+#define AD4691_CNV_DUTY_CYCLE_NS\t\t380\n+\n #define AD4691_SPI_CONFIG_A_REG\t\t\t0x000\n #define AD4691_SW_RESET\t\t\t\t(BIT(7) | BIT(0))\n \n@@ -35,6 +46,7 @@\n #define AD4691_CLAMP_STATUS1_REG\t\t0x01A\n #define AD4691_CLAMP_STATUS2_REG\t\t0x01B\n #define AD4691_DEVICE_SETUP\t\t\t0x020\n+#define AD4691_MANUAL_MODE\t\t\tBIT(2)\n #define AD4691_LDO_EN\t\t\t\tBIT(4)\n #define AD4691_REF_CTRL\t\t\t\t0x021\n #define AD4691_REF_CTRL_MASK\t\t\tGENMASK(4, 2)\n@@ -42,13 +54,18 @@\n #define AD4691_OSC_FREQ_REG\t\t\t0x023\n #define AD4691_OSC_FREQ_MASK\t\t\tGENMASK(3, 0)\n #define AD4691_STD_SEQ_CONFIG\t\t\t0x025\n+#define AD4691_SEQ_ALL_CHANNELS_OFF\t\t0x00\n #define AD4691_SPARE_CONTROL\t\t\t0x02A\n \n+#define AD4691_NOOP\t\t\t\t0x00\n+#define AD4691_ADC_CHAN(ch)\t\t\t((0x10 + (ch)) << 3)\n+\n #define AD4691_OSC_EN_REG\t\t\t0x180\n #define AD4691_STATE_RESET_REG\t\t\t0x181\n #define AD4691_STATE_RESET_ALL\t\t\t0x01\n #define AD4691_ADC_SETUP\t\t\t0x182\n #define AD4691_ADC_MODE_MASK\t\t\tGENMASK(1, 0)\n+#define AD4691_CNV_BURST_MODE\t\t\t0x01\n #define AD4691_AUTONOMOUS_MODE\t\t\t0x02\n /*\n * ACC_MASK_REG covers both mask bytes via ADDR_DESCENDING SPI: writing a\n@@ -58,6 +75,8 @@\n #define AD4691_ACC_DEPTH_IN(n)\t\t\t(0x186 + (n))\n #define AD4691_GPIO_MODE1_REG\t\t\t0x196\n #define AD4691_GPIO_MODE2_REG\t\t\t0x197\n+#define AD4691_GP_MODE_MASK\t\t\tGENMASK(3, 0)\n+#define AD4691_GP_MODE_DATA_READY\t\t0x06\n #define AD4691_GPIO_READ\t\t\t0x1A0\n #define AD4691_ACC_STATUS_FULL1_REG\t\t0x1B0\n #define AD4691_ACC_STATUS_FULL2_REG\t\t0x1B1\n@@ -91,9 +110,11 @@ struct ad4691_chip_info {\n \t\t.type = IIO_VOLTAGE,\t\t\t\t\t\\\n \t\t.indexed = 1,\t\t\t\t\t\t\\\n \t\t.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)\t\t\\\n-\t\t\t\t | BIT(IIO_CHAN_INFO_SAMP_FREQ),\t\\\n+\t\t\t\t | BIT(IIO_CHAN_INFO_SAMP_FREQ)\t\\\n+\t\t\t\t | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),\t\\\n \t\t.info_mask_separate_available =\t\t\t\t\\\n-\t\t\t\t BIT(IIO_CHAN_INFO_SAMP_FREQ),\t\\\n+\t\t\t\t BIT(IIO_CHAN_INFO_SAMP_FREQ)\t\\\n+\t\t\t\t | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),\t\\\n \t\t.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE),\t\\\n \t\t.channel = ch,\t\t\t\t\t\t\\\n \t\t.scan_index = ch,\t\t\t\t\t\\\n@@ -121,6 +142,7 @@ static const struct iio_chan_spec ad4691_channels[] = {\n \tAD4691_CHANNEL(13),\n \tAD4691_CHANNEL(14),\n \tAD4691_CHANNEL(15),\n+\tIIO_CHAN_SOFT_TIMESTAMP(16),\n };\n \n static const struct iio_chan_spec ad4693_channels[] = {\n@@ -132,6 +154,7 @@ static const struct iio_chan_spec ad4693_channels[] = {\n \tAD4691_CHANNEL(5),\n \tAD4691_CHANNEL(6),\n \tAD4691_CHANNEL(7),\n+\tIIO_CHAN_SOFT_TIMESTAMP(8),\n };\n \n /*\n@@ -158,6 +181,14 @@ static const int ad4691_osc_freqs[] = {\n \t1250,\t\t/* 0xF: 1.25 kHz */\n };\n \n+static const char * const ad4691_gp_names[] = { \"gp0\", \"gp1\", \"gp2\", \"gp3\" };\n+\n+/*\n+ * Valid ACC_DEPTH values where the effective divisor equals the count.\n+ * From Table 13: ACC_DEPTH = 2^N yields right-shift = N, divisor = 2^N.\n+ */\n+static const int ad4691_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32 };\n+\n static const struct ad4691_chip_info ad4691_chip_info = {\n \t.channels = ad4691_channels,\n \t.name = \"ad4691\",\n@@ -189,16 +220,55 @@ static const struct ad4691_chip_info ad4694_chip_info = {\n struct ad4691_state {\n \tconst struct ad4691_chip_info *info;\n \tstruct regmap *regmap;\n+\n+\tstruct pwm_device *conv_trigger;\n+\tint irq;\n+\n+\tbool manual_mode;\n+\n \tint vref_uV;\n+\tu8 osr[16];\n \tbool refbuf_en;\n \tbool ldo_en;\n+\tu32 cnv_period_ns;\n \t/*\n \t * Synchronize access to members of the driver state, and ensure\n \t * atomicity of consecutive SPI operations.\n \t */\n \tstruct mutex lock;\n+\t/*\n+\t * Per-buffer-enable lifetime resources:\n+\t * Manual Mode - a pre-built SPI message that clocks out N+1\n+\t *\t\t transfers in one go.\n+\t * CNV Burst Mode - a pre-built SPI message that clocks out 2*N\n+\t *\t\t transfers in one go.\n+\t */\n+\tstruct spi_message scan_msg;\n+\tstruct spi_transfer *scan_xfers;\n+\t__be16 *scan_tx;\n+\t__be16 *scan_rx;\n+\t/* Scan buffer: one slot per channel plus timestamp */\n+\tstruct {\n+\t\tu16 vals[16];\n+\t\taligned_s64 ts;\n+\t} scan __aligned(IIO_DMA_MINALIGN);\n };\n \n+/*\n+ * Configure the given GP pin (0-3) as DATA_READY output.\n+ * GP0/GP1 → GPIO_MODE1_REG, GP2/GP3 → GPIO_MODE2_REG.\n+ * Even pins occupy bits [3:0], odd pins bits [7:4].\n+ */\n+static int ad4691_gpio_setup(struct ad4691_state *st, unsigned int gp_num)\n+{\n+\tunsigned int shift = 4 * (gp_num % 2);\n+\n+\treturn regmap_update_bits(st->regmap,\n+\t\t\t\t AD4691_GPIO_MODE1_REG + gp_num / 2,\n+\t\t\t\t AD4691_GP_MODE_MASK << shift,\n+\t\t\t\t AD4691_GP_MODE_DATA_READY << shift);\n+}\n+\n static int ad4691_reg_read(void *context, unsigned int reg, unsigned int *val)\n {\n \tstruct spi_device *spi = context;\n@@ -359,6 +429,29 @@ static int ad4691_set_sampling_freq(struct iio_dev *indio_dev, int freq)\n \treturn -EINVAL;\n }\n \n+static int ad4691_set_oversampling_ratio(struct iio_dev *indio_dev,\n+\t\t\t\t\t const struct iio_chan_spec *chan,\n+\t\t\t\t\t int osr)\n+{\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios); i++) {\n+\t\tif (ad4691_oversampling_ratios[i] != osr)\n+\t\t\tcontinue;\n+\n+\t\tIIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);\n+\t\tif (IIO_DEV_ACQUIRE_FAILED(claim))\n+\t\t\treturn -EBUSY;\n+\n+\t\tst->osr[chan->scan_index] = osr;\n+\t\treturn regmap_write(st->regmap,\n+\t\t\t\t AD4691_ACC_DEPTH_IN(chan->scan_index), osr);\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n static int ad4691_read_avail(struct iio_dev *indio_dev,\n \t\t\t struct iio_chan_spec const *chan,\n \t\t\t const int **vals, int *type,\n@@ -373,6 +466,11 @@ static int ad4691_read_avail(struct iio_dev *indio_dev,\n \t\t*type = IIO_VAL_INT;\n \t\t*length = ARRAY_SIZE(ad4691_osc_freqs) - start;\n \t\treturn IIO_AVAIL_LIST;\n+\tcase IIO_CHAN_INFO_OVERSAMPLING_RATIO:\n+\t\t*vals = ad4691_oversampling_ratios;\n+\t\t*type = IIO_VAL_INT;\n+\t\t*length = ARRAY_SIZE(ad4691_oversampling_ratios);\n+\t\treturn IIO_AVAIL_LIST;\n \tdefault:\n \t\treturn -EINVAL;\n \t}\n@@ -405,6 +503,11 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev,\n \tif (ret)\n \t\treturn ret;\n \n+\tret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(chan->scan_index),\n+\t\t\t st->osr[chan->scan_index]);\n+\tif (ret)\n+\t\treturn ret;\n+\n \tret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, ®_val);\n \tif (ret)\n \t\treturn ret;\n@@ -414,10 +517,11 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev,\n \t\treturn ret;\n \n \t/*\n-\t * Wait for at least 2 internal oscillator periods for the\n-\t * conversion to complete.\n+\t * Wait for at least 2 internal oscillator periods per accumulation\n+\t * depth for the conversion to complete.\n \t */\n-\tfsleep(DIV_ROUND_UP(2 * USEC_PER_SEC, ad4691_osc_freqs[FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val)]));\n+\tfsleep(DIV_ROUND_UP((unsigned long)st->osr[chan->scan_index] * 2 * USEC_PER_SEC,\n+\t\t\t ad4691_osc_freqs[FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val)]));\n \n \tret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 0);\n \tif (ret)\n@@ -452,6 +556,9 @@ static int ad4691_read_raw(struct iio_dev *indio_dev,\n \t}\n \tcase IIO_CHAN_INFO_SAMP_FREQ:\n \t\treturn ad4691_get_sampling_freq(st, val);\n+\tcase IIO_CHAN_INFO_OVERSAMPLING_RATIO:\n+\t\t*val = st->osr[chan->scan_index];\n+\t\treturn IIO_VAL_INT;\n \tcase IIO_CHAN_INFO_SCALE:\n \t\t*val = st->vref_uV / (MICRO / MILLI);\n \t\t*val2 = chan->scan_type.realbits;\n@@ -468,6 +575,8 @@ static int ad4691_write_raw(struct iio_dev *indio_dev,\n \tswitch (mask) {\n \tcase IIO_CHAN_INFO_SAMP_FREQ:\n \t\treturn ad4691_set_sampling_freq(indio_dev, val);\n+\tcase IIO_CHAN_INFO_OVERSAMPLING_RATIO:\n+\t\treturn ad4691_set_oversampling_ratio(indio_dev, chan, val);\n \tdefault:\n \t\treturn -EINVAL;\n \t}\n@@ -486,6 +595,386 @@ static int ad4691_reg_access(struct iio_dev *indio_dev, unsigned int reg,\n \treturn regmap_write(st->regmap, reg, writeval);\n }\n \n+static int ad4691_set_pwm_freq(struct ad4691_state *st, int freq)\n+{\n+\tif (!freq)\n+\t\treturn -EINVAL;\n+\n+\tst->cnv_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, freq);\n+\treturn 0;\n+}\n+\n+static int ad4691_sampling_enable(struct ad4691_state *st, bool enable)\n+{\n+\tstruct pwm_state conv_state = {\n+\t\t.period = st->cnv_period_ns,\n+\t\t.duty_cycle = AD4691_CNV_DUTY_CYCLE_NS,\n+\t\t.polarity = PWM_POLARITY_NORMAL,\n+\t\t.enabled = enable,\n+\t};\n+\n+\treturn pwm_apply_might_sleep(st->conv_trigger, &conv_state);\n+}\n+\n+/*\n+ * ad4691_enter_conversion_mode - Switch the chip to its buffer conversion mode.\n+ *\n+ * Configures the ADC hardware registers for the mode selected at probe\n+ * (CNV_BURST or MANUAL). Called from buffer preenable before starting\n+ * sampling. The chip is in AUTONOMOUS mode during idle (for read_raw).\n+ */\n+static int ad4691_enter_conversion_mode(struct ad4691_state *st)\n+{\n+\tint ret;\n+\n+\tif (st->manual_mode)\n+\t\treturn regmap_update_bits(st->regmap, AD4691_DEVICE_SETUP,\n+\t\t\t\t\t AD4691_MANUAL_MODE, AD4691_MANUAL_MODE);\n+\n+\tret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP,\n+\t\t\t\t AD4691_ADC_MODE_MASK, AD4691_CNV_BURST_MODE);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_write(st->regmap, AD4691_STATE_RESET_REG,\n+\t\t\t AD4691_STATE_RESET_ALL);\n+}\n+\n+/*\n+ * ad4691_exit_conversion_mode - Return the chip to AUTONOMOUS mode.\n+ *\n+ * Called from buffer postdisable to restore the chip to the\n+ * idle state used by read_raw. Clears the sequencer and resets state.\n+ */\n+static int ad4691_exit_conversion_mode(struct ad4691_state *st)\n+{\n+\tif (st->manual_mode)\n+\t\treturn regmap_update_bits(st->regmap, AD4691_DEVICE_SETUP,\n+\t\t\t\t\t AD4691_MANUAL_MODE, 0);\n+\n+\treturn regmap_update_bits(st->regmap, AD4691_ADC_SETUP,\n+\t\t\t\t AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE);\n+}\n+\n+static void ad4691_free_scan_bufs(struct ad4691_state *st)\n+{\n+\tkfree(st->scan_xfers);\n+\tkfree(st->scan_tx);\n+\tkfree(st->scan_rx);\n+\tst->scan_xfers = NULL;\n+\tst->scan_tx = NULL;\n+\tst->scan_rx = NULL;\n+}\n+\n+static int ad4691_manual_buffer_preenable(struct iio_dev *indio_dev)\n+{\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tstruct device *dev = regmap_get_device(st->regmap);\n+\tstruct spi_device *spi = to_spi_device(dev);\n+\tunsigned int n_active = bitmap_weight(indio_dev->active_scan_mask,\n+\t\t\t\t\t indio_dev->masklength);\n+\tunsigned int n_xfers = n_active + 1;\n+\tunsigned int k, i;\n+\tint ret;\n+\n+\tst->scan_xfers = kcalloc(n_xfers, sizeof(*st->scan_xfers), GFP_KERNEL);\n+\tif (!st->scan_xfers)\n+\t\treturn -ENOMEM;\n+\n+\tst->scan_tx = kcalloc(n_xfers, sizeof(*st->scan_tx), GFP_KERNEL);\n+\tif (!st->scan_tx) {\n+\t\tkfree(st->scan_xfers);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tst->scan_rx = kcalloc(n_xfers, sizeof(*st->scan_rx), GFP_KERNEL);\n+\tif (!st->scan_rx) {\n+\t\tkfree(st->scan_tx);\n+\t\tkfree(st->scan_xfers);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tspi_message_init(&st->scan_msg);\n+\n+\tk = 0;\n+\tiio_for_each_active_channel(indio_dev, i) {\n+\t\tst->scan_tx[k] = cpu_to_be16(AD4691_ADC_CHAN(i));\n+\t\tst->scan_xfers[k].tx_buf = &st->scan_tx[k];\n+\t\tst->scan_xfers[k].rx_buf = &st->scan_rx[k];\n+\t\tst->scan_xfers[k].len = sizeof(__be16);\n+\t\tst->scan_xfers[k].cs_change = 1;\n+\t\tspi_message_add_tail(&st->scan_xfers[k], &st->scan_msg);\n+\t\tk++;\n+\t}\n+\n+\t/* Final NOOP transfer to retrieve last channel's result. */\n+\tst->scan_tx[k] = cpu_to_be16(AD4691_NOOP);\n+\tst->scan_xfers[k].tx_buf = &st->scan_tx[k];\n+\tst->scan_xfers[k].rx_buf = &st->scan_rx[k];\n+\tst->scan_xfers[k].len = sizeof(__be16);\n+\tspi_message_add_tail(&st->scan_xfers[k], &st->scan_msg);\n+\n+\tst->scan_msg.spi = spi;\n+\n+\tret = spi_optimize_message(spi, &st->scan_msg);\n+\tif (ret) {\n+\t\tad4691_free_scan_bufs(st);\n+\t\treturn ret;\n+\t}\n+\n+\tret = ad4691_enter_conversion_mode(st);\n+\tif (ret) {\n+\t\tspi_unoptimize_message(&st->scan_msg);\n+\t\tad4691_free_scan_bufs(st);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ad4691_manual_buffer_postdisable(struct iio_dev *indio_dev)\n+{\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tint ret;\n+\n+\tret = ad4691_exit_conversion_mode(st);\n+\tspi_unoptimize_message(&st->scan_msg);\n+\tad4691_free_scan_bufs(st);\n+\treturn ret;\n+}\n+\n+static const struct iio_buffer_setup_ops ad4691_manual_buffer_setup_ops = {\n+\t.preenable = &ad4691_manual_buffer_preenable,\n+\t.postdisable = &ad4691_manual_buffer_postdisable,\n+};\n+\n+static int ad4691_cnv_burst_buffer_preenable(struct iio_dev *indio_dev)\n+{\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tstruct device *dev = regmap_get_device(st->regmap);\n+\tstruct spi_device *spi = to_spi_device(dev);\n+\tunsigned int n_active = bitmap_weight(indio_dev->active_scan_mask,\n+\t\t\t\t\t indio_dev->masklength);\n+\tunsigned int bit, k, i;\n+\tint ret;\n+\n+\tst->scan_xfers = kcalloc(2 * n_active, sizeof(*st->scan_xfers), GFP_KERNEL);\n+\tif (!st->scan_xfers)\n+\t\treturn -ENOMEM;\n+\n+\tst->scan_tx = kcalloc(n_active, sizeof(*st->scan_tx), GFP_KERNEL);\n+\tif (!st->scan_tx) {\n+\t\tkfree(st->scan_xfers);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tst->scan_rx = kcalloc(n_active, sizeof(*st->scan_rx), GFP_KERNEL);\n+\tif (!st->scan_rx) {\n+\t\tkfree(st->scan_tx);\n+\t\tkfree(st->scan_xfers);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tspi_message_init(&st->scan_msg);\n+\n+\t/*\n+\t * Each AVG_IN read needs two transfers: a 2-byte address write phase\n+\t * followed by a 2-byte data read phase. CS toggles between channels\n+\t * (cs_change=1 on the read phase of all but the last channel).\n+\t */\n+\tk = 0;\n+\tiio_for_each_active_channel(indio_dev, i) {\n+\t\tst->scan_tx[k] = cpu_to_be16(0x8000 | AD4691_AVG_IN(i));\n+\t\tst->scan_xfers[2 * k].tx_buf = &st->scan_tx[k];\n+\t\tst->scan_xfers[2 * k].len = sizeof(__be16);\n+\t\tspi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg);\n+\t\tst->scan_xfers[2 * k + 1].rx_buf = &st->scan_rx[k];\n+\t\tst->scan_xfers[2 * k + 1].len = sizeof(__be16);\n+\t\tif (k < n_active - 1)\n+\t\t\tst->scan_xfers[2 * k + 1].cs_change = 1;\n+\t\tspi_message_add_tail(&st->scan_xfers[2 * k + 1], &st->scan_msg);\n+\t\tk++;\n+\t}\n+\n+\tst->scan_msg.spi = spi;\n+\n+\tret = spi_optimize_message(spi, &st->scan_msg);\n+\tif (ret) {\n+\t\tad4691_free_scan_bufs(st);\n+\t\treturn ret;\n+\t}\n+\n+\tret = regmap_write(st->regmap, AD4691_ACC_MASK_REG,\n+\t\t\t (u16)~bitmap_read(indio_dev->active_scan_mask, 0,\n+\t\t\t\t\t indio_dev->masklength));\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG,\n+\t\t\t bitmap_read(indio_dev->active_scan_mask, 0,\n+\t\t\t\t indio_dev->masklength));\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tiio_for_each_active_channel(indio_dev, bit) {\n+\t\tret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(bit),\n+\t\t\t\t st->osr[bit]);\n+\t\tif (ret)\n+\t\t\tgoto err;\n+\t}\n+\n+\tret = ad4691_enter_conversion_mode(st);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tret = ad4691_sampling_enable(st, true);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tenable_irq(st->irq);\n+\treturn 0;\n+err:\n+\tspi_unoptimize_message(&st->scan_msg);\n+\tad4691_free_scan_bufs(st);\n+\treturn ret;\n+}\n+\n+static int ad4691_cnv_burst_buffer_postdisable(struct iio_dev *indio_dev)\n+{\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tint ret;\n+\n+\tdisable_irq(st->irq);\n+\n+\tret = ad4691_sampling_enable(st, false);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG,\n+\t\t\t AD4691_SEQ_ALL_CHANNELS_OFF);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = ad4691_exit_conversion_mode(st);\n+\tspi_unoptimize_message(&st->scan_msg);\n+\tad4691_free_scan_bufs(st);\n+\treturn ret;\n+}\n+\n+static const struct iio_buffer_setup_ops ad4691_cnv_burst_buffer_setup_ops = {\n+\t.preenable = &ad4691_cnv_burst_buffer_preenable,\n+\t.postdisable = &ad4691_cnv_burst_buffer_postdisable,\n+};\n+\n+static ssize_t sampling_frequency_show(struct device *dev,\n+\t\t\t\t struct device_attribute *attr,\n+\t\t\t\t char *buf)\n+{\n+\tstruct iio_dev *indio_dev = dev_to_iio_dev(dev);\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\n+\treturn sysfs_emit(buf, \"%u\\n\", (u32)(NSEC_PER_SEC / st->cnv_period_ns));\n+}\n+\n+static ssize_t sampling_frequency_store(struct device *dev,\n+\t\t\t\t\tstruct device_attribute *attr,\n+\t\t\t\t\tconst char *buf, size_t len)\n+{\n+\tstruct iio_dev *indio_dev = dev_to_iio_dev(dev);\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tint freq, ret;\n+\n+\tret = kstrtoint(buf, 10, &freq);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tguard(mutex)(&st->lock);\n+\n+\tret = ad4691_set_pwm_freq(st, freq);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn len;\n+}\n+\n+static IIO_DEVICE_ATTR(sampling_frequency, 0644,\n+\t\t sampling_frequency_show,\n+\t\t sampling_frequency_store, 0);\n+\n+static const struct iio_dev_attr *ad4691_buffer_attrs[] = {\n+\t&iio_dev_attr_sampling_frequency,\n+\tNULL\n+};\n+\n+static irqreturn_t ad4691_irq(int irq, void *private)\n+{\n+\tstruct iio_dev *indio_dev = private;\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\n+\t/*\n+\t * GPx has asserted: stop conversions before reading so the\n+\t * accumulator does not continue sampling while the trigger handler\n+\t * processes the data. Then fire the IIO trigger to push the sample\n+\t * to the buffer.\n+\t */\n+\tad4691_sampling_enable(st, false);\n+\tiio_trigger_poll(indio_dev->trig);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static const struct iio_trigger_ops ad4691_trigger_ops = {\n+\t.validate_device = iio_trigger_validate_own_device,\n+};\n+\n+static int ad4691_read_scan(struct iio_dev *indio_dev, s64 timestamp)\n+{\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\tunsigned int i, k = 0;\n+\tint ret;\n+\n+\tguard(mutex)(&st->lock);\n+\n+\tret = spi_sync(st->scan_msg.spi, &st->scan_msg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (st->manual_mode) {\n+\t\tiio_for_each_active_channel(indio_dev, i) {\n+\t\t\tst->scan.vals[i] = be16_to_cpu(st->scan_rx[k + 1]);\n+\t\t\tk++;\n+\t\t}\n+\t} else {\n+\t\tiio_for_each_active_channel(indio_dev, i) {\n+\t\t\tst->scan.vals[i] = be16_to_cpu(st->scan_rx[k]);\n+\t\t\tk++;\n+\t\t}\n+\n+\t\tret = regmap_write(st->regmap, AD4691_STATE_RESET_REG,\n+\t\t\t\t AD4691_STATE_RESET_ALL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = ad4691_sampling_enable(st, true);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\tiio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),\n+\t\t\t\t timestamp);\n+\treturn 0;\n+}\n+\n+static irqreturn_t ad4691_trigger_handler(int irq, void *p)\n+{\n+\tstruct iio_poll_func *pf = p;\n+\tstruct iio_dev *indio_dev = pf->indio_dev;\n+\n+\tad4691_read_scan(indio_dev, pf->timestamp);\n+\tiio_trigger_notify_done(indio_dev->trig);\n+\treturn IRQ_HANDLED;\n+}\n+\n static const struct iio_info ad4691_info = {\n \t.read_raw = &ad4691_read_raw,\n \t.write_raw = &ad4691_write_raw,\n@@ -493,6 +982,18 @@ static const struct iio_info ad4691_info = {\n \t.debugfs_reg_access = &ad4691_reg_access,\n };\n \n+static int ad4691_pwm_setup(struct ad4691_state *st)\n+{\n+\tstruct device *dev = regmap_get_device(st->regmap);\n+\n+\tst->conv_trigger = devm_pwm_get(dev, \"cnv\");\n+\tif (IS_ERR(st->conv_trigger))\n+\t\treturn dev_err_probe(dev, PTR_ERR(st->conv_trigger),\n+\t\t\t\t \"Failed to get cnv pwm\\n\");\n+\n+\treturn ad4691_set_pwm_freq(st, st->info->max_rate);\n+}\n+\n static int ad4691_regulator_setup(struct ad4691_state *st)\n {\n \tstruct device *dev = regmap_get_device(st->regmap);\n@@ -557,8 +1058,25 @@ static int ad4691_config(struct ad4691_state *st)\n {\n \tstruct device *dev = regmap_get_device(st->regmap);\n \tenum ad4691_ref_ctrl ref_val;\n+\tunsigned int gp_num;\n \tint ret;\n \n+\t/*\n+\t * Determine buffer conversion mode from DT: if a PWM is provided it\n+\t * drives the CNV pin (CNV_BURST_MODE); otherwise CNV is tied to CS\n+\t * and each SPI transfer triggers a conversion (MANUAL_MODE).\n+\t * Both modes idle in AUTONOMOUS mode so that read_raw can use the\n+\t * internal oscillator without disturbing the hardware configuration.\n+\t */\n+\tif (device_property_present(dev, \"pwms\")) {\n+\t\tst->manual_mode = false;\n+\t\tret = ad4691_pwm_setup(st);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t} else {\n+\t\tst->manual_mode = true;\n+\t}\n+\n \tswitch (st->vref_uV) {\n \tcase AD4691_VREF_uV_MIN ... AD4691_VREF_2P5_uV_MAX:\n \t\tref_val = AD4691_VREF_2P5;\n@@ -609,7 +1127,87 @@ static int ad4691_config(struct ad4691_state *st)\n \tif (ret)\n \t\treturn dev_err_probe(dev, ret, \"Failed to write ADC_SETUP\\n\");\n \n-\treturn 0;\n+\tif (st->manual_mode)\n+\t\treturn 0;\n+\n+\tfor (gp_num = 0; gp_num < ARRAY_SIZE(ad4691_gp_names); gp_num++) {\n+\t\tif (fwnode_irq_get_byname(dev_fwnode(dev),\n+\t\t\t\t\t ad4691_gp_names[gp_num]) > 0)\n+\t\t\tbreak;\n+\t}\n+\tif (gp_num >= ARRAY_SIZE(ad4691_gp_names))\n+\t\treturn dev_err_probe(dev, -ENODEV,\n+\t\t\t\t \"No valid GP interrupt found\\n\");\n+\n+\treturn ad4691_gpio_setup(st, gp_num);\n+}\n+\n+static int ad4691_setup_triggered_buffer(struct iio_dev *indio_dev,\n+\t\t\t\t\t struct ad4691_state *st)\n+{\n+\tstruct device *dev = regmap_get_device(st->regmap);\n+\tstruct iio_trigger *trig;\n+\tunsigned int i;\n+\tint irq, ret;\n+\n+\ttrig = devm_iio_trigger_alloc(dev, \"%s-dev%d\",\n+\t\t\t\t indio_dev->name,\n+\t\t\t\t iio_device_id(indio_dev));\n+\tif (!trig)\n+\t\treturn -ENOMEM;\n+\n+\ttrig->ops = &ad4691_trigger_ops;\n+\tiio_trigger_set_drvdata(trig, st);\n+\n+\tret = devm_iio_trigger_register(dev, trig);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"IIO trigger register failed\\n\");\n+\n+\tindio_dev->trig = iio_trigger_get(trig);\n+\n+\tif (!st->manual_mode) {\n+\t\t/*\n+\t\t * The GP pin named in interrupt-names asserts at end-of-conversion.\n+\t\t * The IRQ handler stops conversions and fires the IIO trigger so\n+\t\t * the trigger handler can read and push the sample to the buffer.\n+\t\t * The IRQ is kept disabled until the buffer is enabled.\n+\t\t */\n+\t\tirq = -ENODEV;\n+\t\tfor (i = 0; i < ARRAY_SIZE(ad4691_gp_names); i++) {\n+\t\t\tirq = fwnode_irq_get_byname(dev_fwnode(dev),\n+\t\t\t\t\t\t ad4691_gp_names[i]);\n+\t\t\tif (irq > 0)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tif (irq <= 0)\n+\t\t\treturn dev_err_probe(dev, irq < 0 ? irq : -ENODEV,\n+\t\t\t\t\t \"failed to get GP interrupt\\n\");\n+\n+\t\tst->irq = irq;\n+\n+\t\t/*\n+\t\t * IRQ is kept disabled until the buffer is enabled to prevent\n+\t\t * spurious DATA_READY events before the SPI message is set up.\n+\t\t */\n+\t\tret = devm_request_threaded_irq(dev, irq, NULL,\n+\t\t\t\t\t\t&ad4691_irq,\n+\t\t\t\t\t\tIRQF_ONESHOT | IRQF_NO_AUTOEN,\n+\t\t\t\t\t\tindio_dev->name, indio_dev);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\treturn devm_iio_triggered_buffer_setup_ext(dev, indio_dev,\n+\t\t\t\t\t\t\t &iio_pollfunc_store_time,\n+\t\t\t\t\t\t\t &ad4691_trigger_handler,\n+\t\t\t\t\t\t\t IIO_BUFFER_DIRECTION_IN,\n+\t\t\t\t\t\t\t &ad4691_cnv_burst_buffer_setup_ops,\n+\t\t\t\t\t\t\t ad4691_buffer_attrs);\n+\t}\n+\n+\treturn devm_iio_triggered_buffer_setup(dev, indio_dev,\n+\t\t\t\t\t &iio_pollfunc_store_time,\n+\t\t\t\t\t &ad4691_trigger_handler,\n+\t\t\t\t\t &ad4691_manual_buffer_setup_ops);\n }\n \n static int ad4691_probe(struct spi_device *spi)\n@@ -626,6 +1224,8 @@ static int ad4691_probe(struct spi_device *spi)\n \tst = iio_priv(indio_dev);\n \tst->info = spi_get_device_match_data(spi);\n \n+\tmemset(st->osr, 1, sizeof(st->osr));\n+\n \tret = devm_mutex_init(dev, &st->lock);\n \tif (ret)\n \t\treturn ret;\n@@ -654,6 +1254,10 @@ static int ad4691_probe(struct spi_device *spi)\n \tindio_dev->channels = st->info->channels;\n \tindio_dev->num_channels = st->info->num_channels;\n \n+\tret = ad4691_setup_triggered_buffer(indio_dev, st);\n+\tif (ret)\n+\t\treturn ret;\n+\n \treturn devm_iio_device_register(dev, indio_dev);\n }\n \n", "prefixes": [ "v5", "3/4" ] }