get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.1/patches/2223843/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2223843,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2223843/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/patch/20260416-ad4692-multichannel-sar-adc-driver-v8-5-c415bd048fa3@analog.com/",
    "project": {
        "id": 38,
        "url": "http://patchwork.ozlabs.org/api/1.1/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": ""
    },
    "msgid": "<20260416-ad4692-multichannel-sar-adc-driver-v8-5-c415bd048fa3@analog.com>",
    "date": "2026-04-16T09:18:50",
    "name": "[v8,5/6] iio: adc: ad4691: add oversampling support",
    "commit_ref": null,
    "pull_url": null,
    "state": "handled-elsewhere",
    "archived": false,
    "hash": "d3e8c4c89b6666d5e0122ee25d8b72cc57084036",
    "submitter": {
        "id": 92791,
        "url": "http://patchwork.ozlabs.org/api/1.1/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/20260416-ad4692-multichannel-sar-adc-driver-v8-5-c415bd048fa3@analog.com/mbox/",
    "series": [
        {
            "id": 500121,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/500121/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/list/?series=500121",
            "date": "2026-04-16T09:18:45",
            "name": "iio: adc: ad4691: add driver for AD4691 multichannel SAR ADC family",
            "version": 8,
            "mbox": "http://patchwork.ozlabs.org/series/500121/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2223843/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2223843/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "\n <linux-pwm+bounces-8604-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=TlpCNC9i;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-pwm+bounces-8604-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=\"TlpCNC9i\"",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"
        ],
        "Received": [
            "from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::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 4fxCDv12lfz1yG9\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 19:21:19 +1000 (AEST)",
            "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 4B87D304C70D\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 09:19:02 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id A100239B974;\n\tThu, 16 Apr 2026 09:18:52 +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 6567C39A7EC;\n\tThu, 16 Apr 2026 09:18:52 +0000 (UTC)",
            "by smtp.kernel.org (Postfix) with ESMTPS id 3074AC2BCF7;\n\tThu, 16 Apr 2026 09:18:52 +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 290AEF8A14B;\n\tThu, 16 Apr 2026 09:18:52 +0000 (UTC)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776331132; cv=none;\n b=iLusPFKxf8VIo/EvK9jONJJhyv1XggSIUoTA2HrmkmcnXt1/gkSEGnpTrI14Ns3lsmvJOZ8uboW4fgiO11v2nX0SKbl5Rlbvs0VI4tJbyBxpayPUH6XH0r4J56Uvrc/caf6krycB8O+k8Ql/daSpmwtVJV7FayDIKDCBQM/ejmw=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776331132; c=relaxed/simple;\n\tbh=83yNIo9FTqU5fERysZgghlwulMX6cU6V7k+T0H8EVjs=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:\n\t In-Reply-To:To:Cc;\n b=eu1/JSus0AW4mud0jNUp7HVZgBJxaArsR0HBII2GpqdTi4xM5Vb1C+5x8bp6VpYJL0B7Tjp5SKaBEN7UfYKnDfGVXGZaNkwj/zF8auFrxE0pvDekwH4xpmaJ4Kk/yD82r0+NNn5xzh+lb13onki3rGNMIJr/Krk1WDvGjFtrm+Y=",
        "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=TlpCNC9i; 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=1776331132;\n\tbh=83yNIo9FTqU5fERysZgghlwulMX6cU6V7k+T0H8EVjs=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From;\n\tb=TlpCNC9i76eQfFmmbcRcTH11q76lNh/AYuV2x3mQCF9eR888yDCqqfXZqorAd8d/D\n\t OhvrX4tpQDgSBx/ARt4WqKvWdNaUbquz+4vvdBprmTug6benApIrg/GORYR5ZHXtqe\n\t JcKhGLePNN2KdwXft91f7dq1sPcA3TAQxynE29/C4EeFWUHauHPVpdTf7mG/+h76MN\n\t 0Ohoe1bAnJVmCwPdaYLMFbsTsvc+FeCR0j3qD1nsY5RE2GgBLGjZyPm4rZxIlZtb2i\n\t /fpP1lETfYA3wuMYhLqgFb9Pk+Hsv7Y8tYsilpUkARzwUm19avCuOq8Kg/euUqVfiO\n\t 7nYVv6EScSjsA==",
        "From": "Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org>",
        "Date": "Thu, 16 Apr 2026 12:18:50 +0300",
        "Subject": "[PATCH v8 5/6] iio: adc: ad4691: add oversampling 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 <20260416-ad4692-multichannel-sar-adc-driver-v8-5-c415bd048fa3@analog.com>",
        "References": "\n <20260416-ad4692-multichannel-sar-adc-driver-v8-0-c415bd048fa3@analog.com>",
        "In-Reply-To": "\n <20260416-ad4692-multichannel-sar-adc-driver-v8-0-c415bd048fa3@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=1776331127; l=16532;\n i=radu.sabau@analog.com; s=20260220; h=from:subject:message-id;\n bh=n0K/y5C7IZmxkrNiM6UmyZVIAz6TL7shyevZcB+gqoA=;\n b=XS/B1thyqYPnvPo3nYIXIzLHfu/100KztVF35y9jX5ClYZA036iGpzBUrRna9EUUw9iid4lPo\n 0kO/yZ+x9isDssylRJ7V5il9S/EtftF2q3ZkqAT1cOMXbNTvO4hwXQ9",
        "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 per-channel oversampling ratio (OSR) support for CNV burst mode.\nThe accumulator depth register (ACC_DEPTH_IN) is programmed with the\nselected OSR at buffer enable time and before each single-shot read.\n\nSupported OSR values: 1, 2, 4, 8, 16, 32.\n\nIntroduce AD4691_MANUAL_CHANNEL() for manual mode channels, which do\nnot expose the oversampling ratio attribute since OSR is not applicable\nin that mode. A separate manual_channels array is added to\nstruct ad4691_channel_info and selected at probe time; offload paths\nreuse the same arrays with num_channels capping access before the soft\ntimestamp entry.\n\nin_voltageN_sampling_frequency represents the effective output rate for\nchannel N, defined as osc_freq / osr[N]. The chip has one internal\noscillator shared by all channels; each channel independently\naccumulates osr[N] oscillator cycles before producing a result.\n\nWriting sampling_frequency computes needed_osc = freq * osr[N] and\nsnaps down to the largest oscillator table entry that satisfies both\nosc <= needed_osc and osc % osr[N] == 0, guaranteeing an exact integer\nread-back. The result is stored in target_osc_freq_Hz and written to\nOSC_FREQ_REG at buffer enable and single-shot time, so sampling_frequency\nand oversampling_ratio can be set in any order.\n\nin_voltageN_sampling_frequency_available is computed dynamically from\nthe channel's current OSR, listing only oscillator table entries that\ndivide evenly by osr[N], expressed as effective rates. The list becomes\nsparser as OSR increases, capping at max_rate / osr[N].\n\nWriting oversampling_ratio stores the new OSR for that channel;\ntarget_osc_freq_Hz is left unchanged. The effective rate read back via\nin_voltageN_sampling_frequency becomes target_osc_freq_Hz / new_osr\nautomatically. The two attributes are orthogonal: sampling_frequency\ncontrols the oscillator, oversampling_ratio controls the averaging depth.\n\nOSR defaults to 1 (no accumulation) for all channels.\n\nSigned-off-by: Radu Sabau <radu.sabau@analog.com>\n---\n drivers/iio/adc/ad4691.c | 251 +++++++++++++++++++++++++++++++++++++++++------\n 1 file changed, 221 insertions(+), 30 deletions(-)",
    "diff": "diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c\nindex fbd44f595cbe..f000e4cde339 100644\n--- a/drivers/iio/adc/ad4691.c\n+++ b/drivers/iio/adc/ad4691.c\n@@ -115,6 +115,7 @@ enum ad4691_ref_ctrl {\n \n struct ad4691_channel_info {\n \tconst struct iio_chan_spec *channels;\n+\tconst struct iio_chan_spec *manual_channels;\n \tunsigned int num_channels;\n };\n \n@@ -125,7 +126,34 @@ struct ad4691_chip_info {\n \tconst struct ad4691_channel_info *offload_info;\n };\n \n+/* CNV burst mode channel — exposes oversampling ratio. */\n #define AD4691_CHANNEL(ch)\t\t\t\t\t\t\\\n+\t{\t\t\t\t\t\t\t\t\\\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_OVERSAMPLING_RATIO) | \\\n+\t\t\t\t      BIT(IIO_CHAN_INFO_SAMP_FREQ),\t\\\n+\t\t.info_mask_separate_available =\t\t\t\t\\\n+\t\t\t\t      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | \\\n+\t\t\t\t      BIT(IIO_CHAN_INFO_SAMP_FREQ),\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+\t\t.scan_type = {\t\t\t\t\t\t\\\n+\t\t\t.sign = 'u',\t\t\t\t\t\\\n+\t\t\t.realbits = 16,\t\t\t\t\t\\\n+\t\t\t.storagebits = 16,\t\t\t\t\\\n+\t\t\t.endianness = IIO_BE,\t\t\t\t\\\n+\t\t},\t\t\t\t\t\t\t\\\n+\t}\n+\n+/*\n+ * Manual mode channel — no oversampling ratio attribute. OSR is not\n+ * supported in manual mode; ACC_DEPTH_IN is not configured during manual\n+ * buffer enable.\n+ */\n+#define AD4691_MANUAL_CHANNEL(ch)\t\t\t\t\t\\\n \t{\t\t\t\t\t\t\t\t\\\n \t\t.type = IIO_VOLTAGE,\t\t\t\t\t\\\n \t\t.indexed = 1,\t\t\t\t\t\t\\\n@@ -176,25 +204,65 @@ static const struct iio_chan_spec ad4693_channels[] = {\n \tIIO_CHAN_SOFT_TIMESTAMP(8),\n };\n \n+static const struct iio_chan_spec ad4691_manual_channels[] = {\n+\tAD4691_MANUAL_CHANNEL(0),\n+\tAD4691_MANUAL_CHANNEL(1),\n+\tAD4691_MANUAL_CHANNEL(2),\n+\tAD4691_MANUAL_CHANNEL(3),\n+\tAD4691_MANUAL_CHANNEL(4),\n+\tAD4691_MANUAL_CHANNEL(5),\n+\tAD4691_MANUAL_CHANNEL(6),\n+\tAD4691_MANUAL_CHANNEL(7),\n+\tAD4691_MANUAL_CHANNEL(8),\n+\tAD4691_MANUAL_CHANNEL(9),\n+\tAD4691_MANUAL_CHANNEL(10),\n+\tAD4691_MANUAL_CHANNEL(11),\n+\tAD4691_MANUAL_CHANNEL(12),\n+\tAD4691_MANUAL_CHANNEL(13),\n+\tAD4691_MANUAL_CHANNEL(14),\n+\tAD4691_MANUAL_CHANNEL(15),\n+\tIIO_CHAN_SOFT_TIMESTAMP(16),\n+};\n+\n+static const struct iio_chan_spec ad4693_manual_channels[] = {\n+\tAD4691_MANUAL_CHANNEL(0),\n+\tAD4691_MANUAL_CHANNEL(1),\n+\tAD4691_MANUAL_CHANNEL(2),\n+\tAD4691_MANUAL_CHANNEL(3),\n+\tAD4691_MANUAL_CHANNEL(4),\n+\tAD4691_MANUAL_CHANNEL(5),\n+\tAD4691_MANUAL_CHANNEL(6),\n+\tAD4691_MANUAL_CHANNEL(7),\n+\tIIO_CHAN_SOFT_TIMESTAMP(8),\n+};\n+\n+static const int ad4691_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32 };\n+\n static const struct ad4691_channel_info ad4691_sw_info = {\n \t.channels = ad4691_channels,\n+\t.manual_channels = ad4691_manual_channels,\n \t.num_channels = ARRAY_SIZE(ad4691_channels),\n };\n \n static const struct ad4691_channel_info ad4693_sw_info = {\n \t.channels = ad4693_channels,\n+\t.manual_channels = ad4693_manual_channels,\n \t.num_channels = ARRAY_SIZE(ad4693_channels),\n };\n \n static const struct ad4691_channel_info ad4691_offload_info = {\n \t.channels = ad4691_channels,\n-\t/* Exclude the soft timestamp entry; num_channels caps access. */\n+\t/*\n+\t * Offload paths share the SW channel arrays. num_channels caps access\n+\t * before the soft timestamp entry, so no separate array is needed.\n+\t */\n+\t.manual_channels = ad4691_manual_channels,\n \t.num_channels = ARRAY_SIZE(ad4691_channels) - 1,\n };\n \n static const struct ad4691_channel_info ad4693_offload_info = {\n \t.channels = ad4693_channels,\n-\t/* Exclude the soft timestamp entry; num_channels caps access. */\n+\t.manual_channels = ad4693_manual_channels,\n \t.num_channels = ARRAY_SIZE(ad4693_channels) - 1,\n };\n \n@@ -269,6 +337,19 @@ struct ad4691_state {\n \tint irq;\n \tint vref_uV;\n \tu32 cnv_period_ns;\n+\t/*\n+\t * Snapped oscillator frequency (Hz) shared by all channels. Set when\n+\t * sampling_frequency or oversampling_ratio is written; written to\n+\t * OSC_FREQ_REG at buffer enable and single-shot time so both attributes\n+\t * can be set in any order. Reading in_voltageN_sampling_frequency\n+\t * returns target_osc_freq_Hz / osr[N] — the effective rate for that\n+\t * channel given its oversampling ratio.\n+\t */\n+\tu32 target_osc_freq_Hz;\n+\t/* Per-channel oversampling ratio; always 1 in manual mode. */\n+\tu8 osr[16];\n+\t/* Scratch buffer for read_avail SAMP_FREQ; content is OSR-dependent. */\n+\tint samp_freq_avail[ARRAY_SIZE(ad4691_osc_freqs_Hz)];\n \n \tbool manual_mode;\n \tbool refbuf_en;\n@@ -489,6 +570,18 @@ static const struct regmap_config ad4691_regmap_config = {\n \t.cache_type = REGCACHE_MAPLE,\n };\n \n+/* Write target_osc_freq_Hz to OSC_FREQ_REG. Called at use time. */\n+static int ad4691_write_osc_freq(struct ad4691_state *st)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) {\n+\t\tif (ad4691_osc_freqs_Hz[i] == st->target_osc_freq_Hz)\n+\t\t\treturn regmap_write(st->regmap, AD4691_OSC_FREQ_REG, i);\n+\t}\n+\treturn -EINVAL;\n+}\n+\n /*\n  * Index 0 in ad4691_osc_freqs_Hz is 1 MHz — valid only for AD4692/AD4694\n  * (max_rate == 1 MHz). AD4691/AD4693 cap at 500 kHz so their valid range\n@@ -499,36 +592,58 @@ static unsigned int ad4691_samp_freq_start(const struct ad4691_chip_info *info)\n \treturn (info->max_rate == 1 * HZ_PER_MHZ) ? 0 : 1;\n }\n \n-static int ad4691_get_sampling_freq(struct ad4691_state *st, int *val)\n+/*\n+ * Find the largest oscillator table entry that is both <= needed_osc and\n+ * evenly divisible by osr (guaranteeing an integer effective rate on\n+ * read-back). Returns 0 if no such entry exists in the chip's valid range.\n+ */\n+static unsigned int ad4691_find_osc_freq(struct ad4691_state *st,\n+\t\t\t\t\t unsigned int needed_osc,\n+\t\t\t\t\t unsigned int osr)\n {\n-\tunsigned int reg_val;\n-\tint ret;\n+\tunsigned int start = ad4691_samp_freq_start(st->info);\n \n-\tret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, &reg_val);\n-\tif (ret)\n-\t\treturn ret;\n+\tfor (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) {\n+\t\tif ((unsigned int)ad4691_osc_freqs_Hz[i] > needed_osc)\n+\t\t\tcontinue;\n+\t\tif (ad4691_osc_freqs_Hz[i] % osr != 0)\n+\t\t\tcontinue;\n+\t\treturn ad4691_osc_freqs_Hz[i];\n+\t}\n+\treturn 0;\n+}\n \n-\t*val = ad4691_osc_freqs_Hz[FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val)];\n+static int ad4691_get_sampling_freq(struct ad4691_state *st, u8 osr, int *val)\n+{\n+\t*val = st->target_osc_freq_Hz / osr;\n \treturn IIO_VAL_INT;\n }\n \n-static int ad4691_set_sampling_freq(struct iio_dev *indio_dev, int freq)\n+static int ad4691_set_sampling_freq(struct iio_dev *indio_dev,\n+\t\t\t\t    struct iio_chan_spec const *chan, int freq)\n {\n \tstruct ad4691_state *st = iio_priv(indio_dev);\n-\tunsigned int start = ad4691_samp_freq_start(st->info);\n+\tunsigned int osr = st->osr[chan->channel];\n+\tunsigned int found;\n \n \tIIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);\n \tif (IIO_DEV_ACQUIRE_FAILED(claim))\n \t\treturn -EBUSY;\n \n-\tfor (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) {\n-\t\tif (ad4691_osc_freqs_Hz[i] != freq)\n-\t\t\tcontinue;\n-\t\treturn regmap_update_bits(st->regmap, AD4691_OSC_FREQ_REG,\n-\t\t\t\t\t  AD4691_OSC_FREQ_MASK, i);\n-\t}\n+\tif (freq <= 0 || (unsigned int)freq > st->info->max_rate / osr)\n+\t\treturn -EINVAL;\n \n-\treturn -EINVAL;\n+\tfound = ad4691_find_osc_freq(st, (unsigned int)freq * osr, osr);\n+\tif (!found)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * Store the snapped oscillator frequency; OSC_FREQ_REG is written at\n+\t * buffer enable and single-shot time so that sampling_frequency and\n+\t * oversampling_ratio can be set in any order.\n+\t */\n+\tst->target_osc_freq_Hz = found;\n+\treturn 0;\n }\n \n static int ad4691_read_avail(struct iio_dev *indio_dev,\n@@ -540,10 +655,30 @@ static int ad4691_read_avail(struct iio_dev *indio_dev,\n \tunsigned int start = ad4691_samp_freq_start(st->info);\n \n \tswitch (mask) {\n-\tcase IIO_CHAN_INFO_SAMP_FREQ:\n-\t\t*vals = &ad4691_osc_freqs_Hz[start];\n+\tcase IIO_CHAN_INFO_SAMP_FREQ: {\n+\t\tunsigned int osr = st->osr[chan->channel];\n+\t\tint n = 0;\n+\n+\t\t/*\n+\t\t * Only oscillator frequencies evenly divisible by the channel's\n+\t\t * OSR yield an integer effective rate; expose those as effective\n+\t\t * rates (osc / osr) so the user works entirely in output-sample\n+\t\t * space.\n+\t\t */\n+\t\tfor (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) {\n+\t\t\tif (ad4691_osc_freqs_Hz[i] % osr != 0)\n+\t\t\t\tcontinue;\n+\t\t\tst->samp_freq_avail[n++] = ad4691_osc_freqs_Hz[i] / osr;\n+\t\t}\n+\t\t*vals = st->samp_freq_avail;\n \t\t*type = IIO_VAL_INT;\n-\t\t*length = ARRAY_SIZE(ad4691_osc_freqs_Hz) - start;\n+\t\t*length = n;\n+\t\treturn IIO_AVAIL_LIST;\n+\t}\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@@ -554,7 +689,7 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev,\n \t\t\t\t   struct iio_chan_spec const *chan, int *val)\n {\n \tstruct ad4691_state *st = iio_priv(indio_dev);\n-\tunsigned int reg_val, osc_idx, period_us;\n+\tunsigned int reg_val, period_us;\n \tint ret;\n \n \tguard(mutex)(&st->lock);\n@@ -575,7 +710,12 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev,\n \tif (ret)\n \t\treturn ret;\n \n-\tret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, &reg_val);\n+\tret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(chan->channel),\n+\t\t\t   st->osr[chan->channel]);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = ad4691_write_osc_freq(st);\n \tif (ret)\n \t\treturn ret;\n \n@@ -583,9 +723,12 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev,\n \tif (ret)\n \t\treturn ret;\n \n-\tosc_idx = FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val);\n-\t/* Wait 2 oscillator periods for the conversion to complete. */\n-\tperiod_us = DIV_ROUND_UP(2UL * USEC_PER_SEC, ad4691_osc_freqs_Hz[osc_idx]);\n+\t/*\n+\t * Wait osr + 1 oscillator periods: osr for accumulation, +1 for the\n+\t * pipeline margin (one extra period ensures the final result is ready).\n+\t */\n+\tperiod_us = DIV_ROUND_UP((unsigned long)(st->osr[chan->channel] + 1) * USEC_PER_SEC,\n+\t\t\t\t st->target_osc_freq_Hz);\n \tfsleep(period_us);\n \n \tret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 0);\n@@ -620,7 +763,10 @@ static int ad4691_read_raw(struct iio_dev *indio_dev,\n \t\treturn ad4691_single_shot_read(indio_dev, chan, val);\n \t}\n \tcase IIO_CHAN_INFO_SAMP_FREQ:\n-\t\treturn ad4691_get_sampling_freq(st, val);\n+\t\treturn ad4691_get_sampling_freq(st, st->osr[chan->channel], val);\n+\tcase IIO_CHAN_INFO_OVERSAMPLING_RATIO:\n+\t\t*val = st->osr[chan->channel];\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@@ -634,9 +780,29 @@ static int ad4691_write_raw(struct iio_dev *indio_dev,\n \t\t\t    struct iio_chan_spec const *chan,\n \t\t\t    int val, int val2, long mask)\n {\n+\tstruct ad4691_state *st = iio_priv(indio_dev);\n+\n \tswitch (mask) {\n \tcase IIO_CHAN_INFO_SAMP_FREQ:\n-\t\treturn ad4691_set_sampling_freq(indio_dev, val);\n+\t\treturn ad4691_set_sampling_freq(indio_dev, chan, val);\n+\tcase IIO_CHAN_INFO_OVERSAMPLING_RATIO: {\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\tfor (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios); i++) {\n+\t\t\tif (ad4691_oversampling_ratios[i] != val)\n+\t\t\t\tcontinue;\n+\t\t\t/*\n+\t\t\t * Store the new OSR; target_osc_freq_Hz is unchanged.\n+\t\t\t * The effective rate read back via in_voltageN_sampling_frequency\n+\t\t\t * becomes target_osc_freq_Hz / new_osr automatically.\n+\t\t\t */\n+\t\t\tst->osr[chan->channel] = val;\n+\t\t\treturn 0;\n+\t\t}\n+\t\treturn -EINVAL;\n+\t}\n \tdefault:\n \t\treturn -EINVAL;\n \t}\n@@ -691,6 +857,10 @@ static int ad4691_enter_conversion_mode(struct ad4691_state *st)\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 = ad4691_write_osc_freq(st);\n+\tif (ret)\n+\t\treturn ret;\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@@ -844,6 +1014,12 @@ static int ad4691_cnv_burst_buffer_preenable(struct iio_dev *indio_dev)\n \tif (ret)\n \t\tgoto err_unoptimize;\n \n+\tiio_for_each_active_channel(indio_dev, i) {\n+\t\tret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(i), st->osr[i]);\n+\t\tif (ret)\n+\t\t\tgoto err_unoptimize;\n+\t}\n+\n \tret = ad4691_enter_conversion_mode(st);\n \tif (ret)\n \t\tgoto err_unoptimize;\n@@ -995,6 +1171,12 @@ static int ad4691_cnv_burst_offload_buffer_postenable(struct iio_dev *indio_dev)\n \tif (ret)\n \t\treturn ret;\n \n+\tiio_for_each_active_channel(indio_dev, bit) {\n+\t\tret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(bit), st->osr[bit]);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n \tret = ad4691_enter_conversion_mode(st);\n \tif (ret)\n \t\treturn ret;\n@@ -1361,6 +1543,8 @@ static int ad4691_config(struct ad4691_state *st)\n \tif (ret)\n \t\treturn dev_err_probe(dev, ret, \"Failed to write OSC_FREQ\\n\");\n \n+\tst->target_osc_freq_Hz = ad4691_osc_freqs_Hz[ad4691_samp_freq_start(st->info)];\n+\n \tret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP,\n \t\t\t\t AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE);\n \tif (ret)\n@@ -1518,6 +1702,7 @@ static int ad4691_probe(struct spi_device *spi)\n \tst = iio_priv(indio_dev);\n \tst->spi = spi;\n \tst->info = spi_get_device_match_data(spi);\n+\tmemset(st->osr, 1, sizeof(st->osr));\n \n \tret = devm_mutex_init(dev, &st->lock);\n \tif (ret)\n@@ -1552,11 +1737,17 @@ static int ad4691_probe(struct spi_device *spi)\n \tindio_dev->modes = INDIO_DIRECT_MODE;\n \n \tif (spi_offload) {\n-\t\tindio_dev->channels = st->info->offload_info->channels;\n+\t\tif (st->manual_mode)\n+\t\t\tindio_dev->channels = st->info->offload_info->manual_channels;\n+\t\telse\n+\t\t\tindio_dev->channels = st->info->offload_info->channels;\n \t\tindio_dev->num_channels = st->info->offload_info->num_channels;\n \t\tret = ad4691_setup_offload(indio_dev, st, spi_offload);\n \t} else {\n-\t\tindio_dev->channels = st->info->sw_info->channels;\n+\t\tif (st->manual_mode)\n+\t\t\tindio_dev->channels = st->info->sw_info->manual_channels;\n+\t\telse\n+\t\t\tindio_dev->channels = st->info->sw_info->channels;\n \t\tindio_dev->num_channels = st->info->sw_info->num_channels;\n \t\tret = ad4691_setup_triggered_buffer(indio_dev, st);\n \t}\n",
    "prefixes": [
        "v8",
        "5/6"
    ]
}