From nobody Thu Dec 18 07:59:20 2025 Received: from mail-qt1-f175.google.com (mail-qt1-f175.google.com [209.85.160.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 73B261FA251 for ; Tue, 17 Dec 2024 21:47:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734472056; cv=none; b=BNazcqYTrpFL3/kivE9pZSYKu7gFpmkWnsRL8hFNDL3yVDQaJ9L3jKzrWfVYoDs+RgpkpeTIlWkySKfqibdLkoSMTvFF8MmXO9Y6SRL92Y4A3VFgZvL47yos7ilYqzlz3AbNyZUaK9IIJE0DTA5pSt3zI0TgjCNLK2GVpO7gmJs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734472056; c=relaxed/simple; bh=oqeFL/ORw+ie3t+bRwC79nTIAlXNo835EkKO/tgfc5k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IpGkpdZ/um7rmAWeCAH2JZQObncznYNCTyX7mFi+C8unVJ314g8gRKjETLwULnFaUBSZZsROtM3LGBXxRp0lJo/MzB5kUyuq61XmPIS1zdsiDUZiV3OXx3R8jaioUwda92gGEj95uZmrA1d01Dj0ZZiiSc26u8+5MkpvbImq6Lk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=oW9z13v9; arc=none smtp.client-ip=209.85.160.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="oW9z13v9" Received: by mail-qt1-f175.google.com with SMTP id d75a77b69052e-4678afeb133so1444271cf.0 for ; Tue, 17 Dec 2024 13:47:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1734472052; x=1735076852; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=HmKQKY1UbOy/SYoiYy7M4hB5/sLUFqaMhAPy26EnFkc=; b=oW9z13v9nFSOcraZlS7j0nRCxDFS0Knvz7E5fJfLUBCkJxdcMD9N3o6ZCWMHOi6ahZ njLlr524jSfx9d1ZLPwCDA0D0uO6gFRtQ65x9+KA0wkkUSn1Oqa+Skzb+qwgW+AbVLjx Gl29ghOyTy3VWuR8ibpr8RDGL8dYXNYlT5ONOk4Vqepdk81vO9+0ljIP6enR2Pu5QKSg 96s/Xqz9w/lSlUmaBXYuGm4M6XF1hNvp12l9PV0wQEOc6Eer/peRSXl0fIlEUJknE4R4 GrsnyyLgAcZog8Y85w+4aWzfXYrA0WHR4+5LTfagtymImwVX/Z6+P664dKXzdNljAakG JXzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734472052; x=1735076852; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HmKQKY1UbOy/SYoiYy7M4hB5/sLUFqaMhAPy26EnFkc=; b=jzIP2/j2bTnvySsJ0hcWYr5PRP43AZqAVza0jFzwLNScSrf06QZjemOQN/lIEUwpB3 F1yClMOJqZi8uMdvLXETQFfVuhCWTa17GVAmZRPz06WDESxcnXfjCFu3rBNINQYkiNiX EQl1Un5sgBE1YUvIPcfn7/ucf53r3YTkJI5GhLe3VvBM9mawxGauH0H2rENvGGtpMR1J 0CFkMfL9zYj5gNQ3VuXhi7DMy04mDOrAlExL15CtByt8D4Pe777kWplcAJZumlT4Kswb lz02+0Qd0a3M/UdXL/ZkFelrRmQOZGZIJ14AI3wsO4+EZ9PsoMrr1NykdV3JwqFSZzmO kMfg== X-Forwarded-Encrypted: i=1; AJvYcCXUspQWld9NPj4hPhR/0ls9CQeclJ3kKAY6KXP4htSqZYNShUNxJ8Px7qTBZDNu6vAYdmJ0tdT1k456KoU=@vger.kernel.org X-Gm-Message-State: AOJu0Yy9+GMS5tyeSDATpEERNEj1yUgm5eVVk90IxsPSGF4NgXotO1L/ ku8zvewljg9yaiSG3tifRivvWyHwsv2xCO3F+GEYBJoIUiZ9dfWsFkG82vdLL4o= X-Gm-Gg: ASbGncsZ1Uh9OCz6dDjLAy32O35RISBfvVLW2HnXWesCE8L1MKclt44VsDMu69SnTFd BmoUJaK0BrmtVk/gE3PvTaNkk2PKvbGHmSpFj7R9kQvwxKjWlxlOIPiWWe8+GUTGX9knA/9ceF9 sxHiynp+ODQ9w7tqpLA48mp3WQMo62ylZXg6Ag1OPKePkG2TCJTsm9Ei9cFW1oZ4hef057J0j4A 1dze+yLO3tNyfYB8GoQoQ+cSYWhbBZBATONf7aBt5LF1BblJVCPb3NpFCer3bSDZaF38cubZbtr nZxuAqIkGh2y3Rhf X-Google-Smtp-Source: AGHT+IHVte31Gj67biWkHxDzyWnTTL0jqqRuzWN4Ql8MYbOrKsQvNiHhcUz+ygxkU9R5WWHSyqX3/A== X-Received: by 2002:ac8:580d:0:b0:467:6a8d:e01d with SMTP id d75a77b69052e-469090a8af3mr7124131cf.18.1734472052285; Tue, 17 Dec 2024 13:47:32 -0800 (PST) Received: from localhost (d24-150-219-207.home.cgocable.net. [24.150.219.207]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-467b2ca087esm43783041cf.28.2024.12.17.13.47.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Dec 2024 13:47:31 -0800 (PST) From: Trevor Gamblin Date: Tue, 17 Dec 2024 16:47:28 -0500 Subject: [PATCH 1/2] iio: adc: ad4695: add offload-based oversampling support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241217-ad4695-oversampling-v1-1-0b045d835dac@baylibre.com> References: <20241217-ad4695-oversampling-v1-0-0b045d835dac@baylibre.com> In-Reply-To: <20241217-ad4695-oversampling-v1-0-0b045d835dac@baylibre.com> To: Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , David Lechner , Lars-Peter Clausen , Jonathan Cameron , Jonathan Corbet Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Trevor Gamblin X-Mailer: b4 0.14.1 Add support for the ad4695's oversampling feature when SPI offload is available. This allows the ad4695 to set oversampling ratios on a per-channel basis, raising the effective-number-of-bits from 16 (OSR =3D=3D 1) to 17 (4), 18 (16), or 19 (64) for a given sample (i.e. one full cycle through the auto-sequencer). The logic for reading and writing sampling frequency for a given channel is also adjusted based on the current oversampling ratio. The non-offload case isn't supported as there isn't a good way to trigger the CNV pin in this mode. Support could be added in the future if a use-case arises. Signed-off-by: Trevor Gamblin --- drivers/iio/adc/ad4695.c | 378 +++++++++++++++++++++++++++++++++++++++++++= ---- 1 file changed, 348 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c index c8cd73d19e86..320f2c1a0877 100644 --- a/drivers/iio/adc/ad4695.c +++ b/drivers/iio/adc/ad4695.c @@ -79,6 +79,7 @@ #define AD4695_REG_CONFIG_IN_MODE BIT(6) #define AD4695_REG_CONFIG_IN_PAIR GENMASK(5, 4) #define AD4695_REG_CONFIG_IN_AINHIGHZ_EN BIT(3) +#define AD4695_REG_CONFIG_IN_OSR_SET GENMASK(1, 0) #define AD4695_REG_UPPER_IN(n) (0x0040 | (2 * (n))) #define AD4695_REG_LOWER_IN(n) (0x0060 | (2 * (n))) #define AD4695_REG_HYST_IN(n) (0x0080 | (2 * (n))) @@ -127,6 +128,7 @@ struct ad4695_channel_config { bool bipolar; enum ad4695_in_pair pin_pairing; unsigned int common_mode_mv; + unsigned int oversampling_ratio; }; =20 struct ad4695_state { @@ -306,6 +308,65 @@ static const struct regmap_bus ad4695_regmap_bus =3D { .val_format_endian_default =3D REGMAP_ENDIAN_BIG, }; =20 +enum { + AD4695_SCAN_TYPE_OSR_1, + AD4695_SCAN_TYPE_OSR_4, + AD4695_SCAN_TYPE_OSR_16, + AD4695_SCAN_TYPE_OSR_64, +}; + +static const struct iio_scan_type ad4695_scan_type_offload_u[] =3D { + [AD4695_SCAN_TYPE_OSR_1] =3D { + .sign =3D 'u', + .realbits =3D 16, + .shift =3D 3, + .storagebits =3D 32, + }, + [AD4695_SCAN_TYPE_OSR_4] =3D { + .sign =3D 'u', + .realbits =3D 17, + .shift =3D 2, + .storagebits =3D 32, + }, + [AD4695_SCAN_TYPE_OSR_16] =3D { + .sign =3D 'u', + .realbits =3D 18, + .shift =3D 1, + .storagebits =3D 32, + }, + [AD4695_SCAN_TYPE_OSR_64] =3D { + .sign =3D 'u', + .realbits =3D 19, + .storagebits =3D 32, + }, +}; + +static const struct iio_scan_type ad4695_scan_type_offload_s[] =3D { + [AD4695_SCAN_TYPE_OSR_1] =3D { + .sign =3D 's', + .realbits =3D 16, + .shift =3D 3, + .storagebits =3D 32, + }, + [AD4695_SCAN_TYPE_OSR_4] =3D { + .sign =3D 's', + .realbits =3D 17, + .shift =3D 2, + .storagebits =3D 32, + }, + [AD4695_SCAN_TYPE_OSR_16] =3D { + .sign =3D 's', + .realbits =3D 18, + .shift =3D 1, + .storagebits =3D 32, + }, + [AD4695_SCAN_TYPE_OSR_64] =3D { + .sign =3D 's', + .realbits =3D 19, + .storagebits =3D 32, + }, +}; + static const struct iio_chan_spec ad4695_channel_template =3D { .type =3D IIO_VOLTAGE, .indexed =3D 1, @@ -343,6 +404,10 @@ static const char * const ad4695_power_supplies[] =3D { "avdd", "vio" }; =20 +static const int ad4695_oversampling_ratios[] =3D { + 1, 4, 16, 64, +}; + static const struct ad4695_chip_info ad4695_chip_info =3D { .name =3D "ad4695", .max_sample_rate =3D 500 * KILO, @@ -519,6 +584,29 @@ static int ad4695_set_ref_voltage(struct ad4695_state = *st, int vref_mv) FIELD_PREP(AD4695_REG_REF_CTRL_VREF_SET, val)); } =20 +/** + * ad4695_osr_to_regval - convert ratio to OSR register value + * @ratio: ratio to check + * + * Check if ratio is present in the list of available ratios and return + * the corresponding value that needs to be written to the register to + * select that ratio. + * + * Returns: register value (0 to 3) or -EINVAL if there is not an exact + * match + */ +static int ad4695_osr_to_regval(int ratio) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(ad4695_oversampling_ratios); i++) { + if (ratio =3D=3D ad4695_oversampling_ratios[i]) + return i; + } + + return -EINVAL; +} + static int ad4695_write_chn_cfg(struct ad4695_state *st, struct ad4695_channel_config *cfg) { @@ -945,10 +1033,18 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct ad4695_state *st =3D iio_priv(indio_dev); + const struct iio_scan_type *scan_type; struct ad4695_channel_config *cfg =3D &st->channels_cfg[chan->scan_index]; - u8 realbits =3D chan->scan_type.realbits; + unsigned int osr =3D st->channels_cfg[chan->scan_index].oversampling_rati= o; unsigned int reg_val; int ret, tmp; + u8 realbits; + + scan_type =3D iio_get_current_scan_type(indio_dev, chan); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + realbits =3D scan_type->realbits; =20 switch (mask) { case IIO_CHAN_INFO_RAW: @@ -957,7 +1053,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, if (ret) return ret; =20 - if (chan->scan_type.sign =3D=3D 's') + if (scan_type->sign =3D=3D 's') *val =3D sign_extend32(st->raw_data, realbits - 1); else *val =3D st->raw_data; @@ -969,7 +1065,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_VOLTAGE: *val =3D st->vref_mv; - *val2 =3D chan->scan_type.realbits; + *val2 =3D realbits; return IIO_VAL_FRACTIONAL_LOG2; case IIO_TEMP: /* T_scale (=C2=B0C) =3D raw * V_REF (mV) / (-1.8 mV/=C2=B0C * 2^16) */ @@ -1030,8 +1126,26 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, =20 tmp =3D sign_extend32(reg_val, 15); =20 - *val =3D tmp / 4; - *val2 =3D abs(tmp) % 4 * MICRO / 4; + switch (cfg->oversampling_ratio) { + case 1: + *val =3D tmp / 4; + *val2 =3D abs(tmp) % 4 * MICRO / 4; + break; + case 4: + *val =3D tmp / 2; + *val2 =3D abs(tmp) % 2 * MICRO / 2; + break; + case 16: + *val =3D tmp; + *val2 =3D 0; + break; + case 64: + *val =3D tmp * 2; + *val2 =3D 0; + break; + default: + return -EINVAL; + } =20 if (tmp < 0 && *val2) { *val *=3D -1; @@ -1044,6 +1158,14 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_VOLTAGE: + *val =3D st->channels_cfg[chan->scan_index].oversampling_ratio; + return IIO_VAL_INT; + default: + return -EINVAL; + } case IIO_CHAN_INFO_SAMP_FREQ: { struct pwm_state state; =20 @@ -1051,7 +1173,11 @@ static int ad4695_read_raw(struct iio_dev *indio_dev, if (ret) return ret; =20 - *val =3D DIV_ROUND_UP_ULL(NSEC_PER_SEC, state.period); + /* + * The effective sampling frequency for a channel is the input + * frequency divided by the channel's OSR value. + */ + *val =3D DIV_ROUND_UP_ULL(NSEC_PER_SEC, state.period * osr); =20 return IIO_VAL_INT; } @@ -1072,12 +1198,114 @@ static int ad4695_write_raw_get_fmt(struct iio_dev= *indio_dev, } } =20 +static int ad4695_set_osr_val(struct ad4695_state *st, + struct iio_chan_spec const *chan, + int val) +{ + int osr =3D ad4695_osr_to_regval(val); + + if (osr < 0) + return osr; + + switch (chan->type) { + case IIO_VOLTAGE: + st->channels_cfg[chan->scan_index].oversampling_ratio =3D val; + return regmap_update_bits(st->regmap, + AD4695_REG_CONFIG_IN(chan->scan_index), + AD4695_REG_CONFIG_IN_OSR_SET, + FIELD_PREP(AD4695_REG_CONFIG_IN_OSR_SET, osr)); + default: + return -EINVAL; + } +} + +static unsigned int ad4695_get_calibbias(int val, int val2, int osr) +{ + unsigned int reg_val; + + switch (osr) { + case 4: + if (val2 >=3D 0 && val > S16_MAX / 2) + reg_val =3D S16_MAX; + else if ((val2 < 0 ? -val : val) < S16_MIN / 2) + reg_val =3D S16_MIN; + else if (val2 < 0) + reg_val =3D clamp_t(int, + -(val * 2 + -val2 * 2 / MICRO), + S16_MIN, S16_MAX); + else if (val < 0) + reg_val =3D clamp_t(int, + val * 2 - val2 * 2 / MICRO, + S16_MIN, S16_MAX); + else + reg_val =3D clamp_t(int, + val * 2 + val2 * 2 / MICRO, + S16_MIN, S16_MAX); + return reg_val; + case 16: + if (val2 >=3D 0 && val > S16_MAX) + reg_val =3D S16_MAX; + else if ((val2 < 0 ? -val : val) < S16_MIN) + reg_val =3D S16_MIN; + else if (val2 < 0) + reg_val =3D clamp_t(int, + -(val + -val2 / MICRO), + S16_MIN, S16_MAX); + else if (val < 0) + reg_val =3D clamp_t(int, + val - val2 / MICRO, + S16_MIN, S16_MAX); + else + reg_val =3D clamp_t(int, + val + val2 / MICRO, + S16_MIN, S16_MAX); + return reg_val; + case 64: + if (val2 >=3D 0 && val > S16_MAX * 2) + reg_val =3D S16_MAX; + else if ((val2 < 0 ? -val : val) < S16_MIN * 2) + reg_val =3D S16_MIN; + else if (val2 < 0) + reg_val =3D clamp_t(int, + -(val / 2 + -val2 / 2 / MICRO), + S16_MIN, S16_MAX); + else if (val < 0) + reg_val =3D clamp_t(int, + val / 2 - val2 / 2 / MICRO, + S16_MIN, S16_MAX); + else + reg_val =3D clamp_t(int, + val / 2 + val2 / 2 / MICRO, + S16_MIN, S16_MAX); + return reg_val; + default: + if (val2 >=3D 0 && val > S16_MAX / 4) + reg_val =3D S16_MAX; + else if ((val2 < 0 ? -val : val) < S16_MIN / 4) + reg_val =3D S16_MIN; + else if (val2 < 0) + reg_val =3D clamp_t(int, + -(val * 4 + -val2 * 4 / MICRO), + S16_MIN, S16_MAX); + else if (val < 0) + reg_val =3D clamp_t(int, + val * 4 - val2 * 4 / MICRO, + S16_MIN, S16_MAX); + else + reg_val =3D clamp_t(int, + val * 4 + val2 * 4 / MICRO, + S16_MIN, S16_MAX); + return reg_val; + } +} + static int ad4695_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct ad4695_state *st =3D iio_priv(indio_dev); unsigned int reg_val; + unsigned int osr =3D st->channels_cfg[chan->scan_index].oversampling_rati= o; =20 iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { switch (mask) { @@ -1102,23 +1330,7 @@ static int ad4695_write_raw(struct iio_dev *indio_de= v, case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_VOLTAGE: - if (val2 >=3D 0 && val > S16_MAX / 4) - reg_val =3D S16_MAX; - else if ((val2 < 0 ? -val : val) < S16_MIN / 4) - reg_val =3D S16_MIN; - else if (val2 < 0) - reg_val =3D clamp_t(int, - -(val * 4 + -val2 * 4 / MICRO), - S16_MIN, S16_MAX); - else if (val < 0) - reg_val =3D clamp_t(int, - val * 4 - val2 * 4 / MICRO, - S16_MIN, S16_MAX); - else - reg_val =3D clamp_t(int, - val * 4 + val2 * 4 / MICRO, - S16_MIN, S16_MAX); - + reg_val =3D ad4695_get_calibbias(val, val2, osr); return regmap_write(st->regmap16, AD4695_REG_OFFSET_IN(chan->scan_index), reg_val); @@ -1127,15 +1339,27 @@ static int ad4695_write_raw(struct iio_dev *indio_d= ev, } case IIO_CHAN_INFO_SAMP_FREQ: { struct pwm_state state; - - if (val <=3D 0 || val > st->chip_info->max_sample_rate) + /* + * Limit the maximum acceptable sample rate according to + * the channel's oversampling ratio. + */ + u64 max_osr_rate =3D DIV_ROUND_UP_ULL(st->chip_info->max_sample_rate, + osr); + + if (val <=3D 0 || val > max_osr_rate) return -EINVAL; =20 guard(mutex)(&st->cnv_pwm_lock); pwm_get_state(st->cnv_pwm, &state); - state.period =3D DIV_ROUND_UP_ULL(NSEC_PER_SEC, val); + /* + * The required sample frequency for a given OSR is the + * input frequency multiplied by it. + */ + state.period =3D DIV_ROUND_UP_ULL(NSEC_PER_SEC, val * osr); return pwm_apply_might_sleep(st->cnv_pwm, &state); } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return ad4695_set_osr_val(st, chan, val); default: return -EINVAL; } @@ -1148,18 +1372,40 @@ static int ad4695_read_avail(struct iio_dev *indio_= dev, const int **vals, int *type, int *length, long mask) { + int ret; static const int ad4695_calibscale_available[6] =3D { /* Range of 0 (inclusive) to 2 (exclusive) */ 0, 15, 1, 15, U16_MAX, 15 }; - static const int ad4695_calibbias_available[6] =3D { + static const int ad4695_calibbias_available[4][6] =3D { /* * Datasheet says FSR/8 which translates to signed/4. The step - * depends on oversampling ratio which is always 1 for now. + * depends on oversampling ratio, so we need four different + * ranges to select from. */ - S16_MIN / 4, 0, 0, MICRO / 4, S16_MAX / 4, S16_MAX % 4 * MICRO / 4 + { + S16_MIN / 4, 0, + 0, MICRO / 4, + S16_MAX / 4, S16_MAX % 4 * MICRO / 4 + }, + { + S16_MIN / 2, 0, + 0, MICRO / 2, + S16_MAX / 2, S16_MAX % 2 * MICRO / 2, + }, + { + S16_MIN, 0, + 1, 0, + S16_MAX, 0, + }, + { + S16_MIN * 2, 0, + 2, 0, + S16_MAX * 2, 0, + }, }; struct ad4695_state *st =3D iio_priv(indio_dev); + unsigned int osr =3D st->channels_cfg[chan->scan_index].oversampling_rati= o; =20 switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: @@ -1174,16 +1420,36 @@ static int ad4695_read_avail(struct iio_dev *indio_= dev, case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_VOLTAGE: - *vals =3D ad4695_calibbias_available; + ret =3D ad4695_osr_to_regval(osr); + if (ret < 0) + return ret; + /* + * Select the appropriate calibbias array based on the + * OSR value in the register. + */ + *vals =3D ad4695_calibbias_available[ret]; *type =3D IIO_VAL_INT_PLUS_MICRO; return IIO_AVAIL_RANGE; default: return -EINVAL; } case IIO_CHAN_INFO_SAMP_FREQ: + /* Max sample rate for the channel depends on OSR */ + st->sample_freq_range[2] =3D + DIV_ROUND_UP_ULL(st->chip_info->max_sample_rate, osr); *vals =3D st->sample_freq_range; *type =3D IIO_VAL_INT; return IIO_AVAIL_RANGE; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_VOLTAGE: + *vals =3D ad4695_oversampling_ratios; + *length =3D ARRAY_SIZE(ad4695_oversampling_ratios); + *type =3D IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } default: return -EINVAL; } @@ -1217,6 +1483,26 @@ static int ad4695_debugfs_reg_access(struct iio_dev = *indio_dev, return -EINVAL; } =20 +static int ad4695_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad4695_state *st =3D iio_priv(indio_dev); + unsigned int osr =3D st->channels_cfg[chan->scan_index].oversampling_rati= o; + + switch (osr) { + case 1: + return AD4695_SCAN_TYPE_OSR_1; + case 4: + return AD4695_SCAN_TYPE_OSR_4; + case 16: + return AD4695_SCAN_TYPE_OSR_16; + case 64: + return AD4695_SCAN_TYPE_OSR_64; + default: + return -EINVAL; + } +} + static const struct iio_info ad4695_info =3D { .read_raw =3D &ad4695_read_raw, .write_raw_get_fmt =3D &ad4695_write_raw_get_fmt, @@ -1225,6 +1511,15 @@ static const struct iio_info ad4695_info =3D { .debugfs_reg_access =3D &ad4695_debugfs_reg_access, }; =20 +static const struct iio_info ad4695_offload_info =3D { + .read_raw =3D &ad4695_read_raw, + .write_raw_get_fmt =3D &ad4695_write_raw_get_fmt, + .write_raw =3D &ad4695_write_raw, + .get_current_scan_type =3D &ad4695_get_current_scan_type, + .read_avail =3D &ad4695_read_avail, + .debugfs_reg_access =3D &ad4695_debugfs_reg_access, +}; + static int ad4695_parse_channel_cfg(struct ad4695_state *st) { struct device *dev =3D &st->spi->dev; @@ -1240,6 +1535,9 @@ static int ad4695_parse_channel_cfg(struct ad4695_sta= te *st) chan_cfg->highz_en =3D true; chan_cfg->channel =3D i; =20 + /* This is the default OSR after reset */ + chan_cfg->oversampling_ratio =3D 1; + *iio_chan =3D ad4695_channel_template; iio_chan->channel =3D i; iio_chan->scan_index =3D i; @@ -1408,6 +1706,7 @@ static int ad4695_probe_spi_offload(struct iio_dev *i= ndio_dev, struct dma_chan *rx_dma; int ret, i; =20 + indio_dev->info =3D &ad4695_offload_info; indio_dev->num_channels =3D st->chip_info->num_voltage_inputs + 1; indio_dev->setup_ops =3D &ad4695_offload_buffer_setup_ops; =20 @@ -1458,6 +1757,7 @@ static int ad4695_probe_spi_offload(struct iio_dev *i= ndio_dev, =20 for (i =3D 0; i < indio_dev->num_channels; i++) { struct iio_chan_spec *chan =3D &st->iio_chan[i]; + struct ad4695_channel_config *cfg =3D &st->channels_cfg[i]; =20 /* * NB: When using offload support, all channels need to have the @@ -1473,6 +1773,24 @@ static int ad4695_probe_spi_offload(struct iio_dev *= indio_dev, /* add sample frequency for PWM CNV trigger */ chan->info_mask_separate |=3D BIT(IIO_CHAN_INFO_SAMP_FREQ); chan->info_mask_separate_available |=3D BIT(IIO_CHAN_INFO_SAMP_FREQ); + + /* Add the oversampling properties only for voltage channels */ + if (chan->type !=3D IIO_VOLTAGE) + continue; + + chan->info_mask_separate |=3D BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + chan->info_mask_separate_available |=3D + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + chan->has_ext_scan_type =3D 1; + if (cfg->bipolar) { + chan->ext_scan_type =3D ad4695_scan_type_offload_s; + chan->num_ext_scan_type =3D + ARRAY_SIZE(ad4695_scan_type_offload_s); + } else { + chan->ext_scan_type =3D ad4695_scan_type_offload_u; + chan->num_ext_scan_type =3D + ARRAY_SIZE(ad4695_scan_type_offload_u); + } } =20 return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, --=20 2.39.5 From nobody Thu Dec 18 07:59:20 2025 Received: from mail-qv1-f43.google.com (mail-qv1-f43.google.com [209.85.219.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D42D1F9AAC for ; Tue, 17 Dec 2024 21:47:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734472057; cv=none; b=JuSBlyfJ4+YgrNPforZ+lYnHA2vSJ80gkNHnW6UciYc4EX1U9/M43nrtWOaGo42JewfwVzzcUoVNtM36fIzJ6noavejRXCx7C4XsMIZRefFL2HPO4DqYLaUmVWzXZGBLNheDuMBISOk/251OHt/yKcYQV0aShlXHKI5Fn16w1no= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734472057; c=relaxed/simple; bh=Ma8HaBPEK9LBfvT3QeN1X7ugzAmaSGzcmCUpk/9AAyw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=l9s7eTQTUWMDCk0p3MirFQ4k0v2/dJjXvBigq4PVkz2NjVy/fcNrsf3nW5kXuzkK33ZPmXqSLl5b7/V+X0Tdokvtg0Rur3HiYjeBSjJ4NtKNcam+TJw2QW8M6F1c4Yz288w8CFpREoh2SC/Zy/4xJmhsWh2oqtAGsjhVDx3Os+8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=T6HN/vE+; arc=none smtp.client-ip=209.85.219.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="T6HN/vE+" Received: by mail-qv1-f43.google.com with SMTP id 6a1803df08f44-6dcdf23b4edso25780376d6.0 for ; Tue, 17 Dec 2024 13:47:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1734472053; x=1735076853; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=p2jerrcD1nGClFF+pwwbUr/tdkat4xQ5wJ8skGDMH+c=; b=T6HN/vE+AG1yAlw02+JsgBOjLd6ioFgjFxxMSDre/og/BQY5+DAFhBDM6+h8Lnc0xB pEuEgRZs/HFkLS6k1bBwP4X+NaAEEJB1a/cg2pkHYn1MiYH502QbhoSbIhzFNEHiPyRj 4n2/mq+s2v6/l0v5o5GVEG7BBd8pU8lIVp0QkZgQyBq829Z+dziFRQSBDc1BVjywGTZT Ue157lr32GqmhEbOFW+zoN3yL0D4DWApacpUfLvCmWGCWhyymQLOWfzIF8EwTf/Vtasc chdsxy5yIuVaQlcs0wG6Y6cllTpAD9NWrGcP8idoY+HIrnRACKx5k2uA6SbJUs4g27Zm h3Qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734472053; x=1735076853; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=p2jerrcD1nGClFF+pwwbUr/tdkat4xQ5wJ8skGDMH+c=; b=qn80i5mDICNrPHDIoTwL/ZrL6Sg4IZSUzb/4DrQRXwpFr6jcRQz3Z5S7/P5AHT9Pv7 zxfnbbfssfA+bTHAlwJK0YJtH/pky3TR9gSmAWhDLcM12mOZ4Wuxvn9mtAATXA3AICXA sYP4Hw2b/sCl6aMVxh71KqdRguBoFfZ7JBOHV8nIN97heoL+HR29WzSS/M4ViRiO3zdE 70AyZz+Si3IWE3lk7hJLKpBenJAXmZWicOfUNxwVlZ0k/Td7VTNp/BN/lhZNL4tCgoYE hzGPYTrg5v+rWb+50ULNDSt1GBAEZ7ym3NT3O+UNyanrX5O5AY23yH20umJwTvRDWPD4 6RdQ== X-Forwarded-Encrypted: i=1; AJvYcCUptUqd52cfTh6uWj/ZDQVeZhh4jbDvf+43jJRfOfyP3tX7QLsF7Qv1URbdUsT59z4+DzY1cdrdFSBGCbc=@vger.kernel.org X-Gm-Message-State: AOJu0YyqC+VZW28E8yDPWzcfcSyfWWaWz3yytZENh35COpDU1AbTpCLC Tl4eLhMEISO43mWPf8QrcSjfNwjAPbWhcOjJyZN0+JHYMwf1LwqMIfpF2Knb57iBJ27sOUXCygj J X-Gm-Gg: ASbGncuLVJfU25i/YnB85YaeKbZz061O4RNIUKRTL8dbmNbvtWxvhkw5uGG4D06QhiP P/69beSm0QpmZSWRZPFyWJFUwf6CwrED8i03N22k1PlfqvT/cpPUKQjEghmlLTta+SZyxUKds1O 1sva8AIIpdOFCXN4rSgbg5tmwa/hQutlkfPD5Iwu7jJwXLvv3NZIA2RK9SvcU+WiZbCqIsN9Q0y Rn2qrsLg49g5xZBUWyl1RznMt2a+WQcjlOVJTWx4lKN2zUcCq8oW44S09Xf0aEIypyJusPB8AtN HbCk8vkncCo+/GnK X-Google-Smtp-Source: AGHT+IGfUKqTzhb+KyEvQJ+1fmr9Oi39Z91ue5ioU5B1N5OQfbf8bpjZTFXWHo4XK9ki9DBrVjqWDg== X-Received: by 2002:a05:6214:1301:b0:6d8:8667:c6ca with SMTP id 6a1803df08f44-6dd09241f5emr12256036d6.32.1734472053451; Tue, 17 Dec 2024 13:47:33 -0800 (PST) Received: from localhost (d24-150-219-207.home.cgocable.net. [24.150.219.207]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6dccd22f0b7sm43260876d6.23.2024.12.17.13.47.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Dec 2024 13:47:33 -0800 (PST) From: Trevor Gamblin Date: Tue, 17 Dec 2024 16:47:29 -0500 Subject: [PATCH 2/2] doc: iio: ad4695: describe oversampling support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241217-ad4695-oversampling-v1-2-0b045d835dac@baylibre.com> References: <20241217-ad4695-oversampling-v1-0-0b045d835dac@baylibre.com> In-Reply-To: <20241217-ad4695-oversampling-v1-0-0b045d835dac@baylibre.com> To: Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , David Lechner , Lars-Peter Clausen , Jonathan Cameron , Jonathan Corbet Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Trevor Gamblin X-Mailer: b4 0.14.1 Add a section to the ad4695 documentation describing how to use the oversampling feature. Also add some clarification on how the oversampling ratio influences effective sample rate in the offload section. Signed-off-by: Trevor Gamblin --- Documentation/iio/ad4695.rst | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/iio/ad4695.rst b/Documentation/iio/ad4695.rst index ead0faadff4b..f40593bcc37d 100644 --- a/Documentation/iio/ad4695.rst +++ b/Documentation/iio/ad4695.rst @@ -179,12 +179,38 @@ Gain/offset calibration System calibration is supported using the channel gain and offset register= s via the ``calibscale`` and ``calibbias`` attributes respectively. =20 +Oversampling +------------ + +The chip supports per-channel oversampling when SPI offload is being used,= with +available oversampling ratios (OSR) of 1 (default), 4, 16, and 64. Enabli= ng +oversampling on a channel raises the effective number of bits of sampled d= ata to +17 (OSR =3D=3D 4), 18 (16), or 19 (64), respectively. This can be set via = the +``oversampling_ratio`` attribute. + +Setting the oversampling ratio for a channel also changes the sample rate = for +that channel, since it requires multiple conversions per 1 sample. Specifi= cally, +the new sampling frequency is the PWM sampling frequency divided by the +particular OSR. This is set automatically by the driver when setting the +``oversampling_ratio`` attribute. For example, if the device's current +``sampling_frequency`` is 10000 and an OSR of 4 is set on channel ``voltag= e0``, +the new reported sampling rate for that channel will be 2500 (ignoring PWM= API +rounding), while all others will remain at 10000. Subsequently setting the +sampling frequency to a higher value on that channel will adjust the CNV t= rigger +period for all channels, e.g. if ``voltage0``'s sampling frequency is adju= sted +from 2500 (with an OSR of 4) to 10000, the value reported by +``in_voltage0_sampling_frequency`` will be 10000, but all other channels w= ill +now report 40000. + +For simplicity, the sampling frequency of the device should be set (consid= ering +the highest desired OSR value to be used) first, before configuring oversa= mpling +for specific channels. + Unimplemented features ---------------------- =20 - Additional wiring modes - Threshold events -- Oversampling - GPIO support - CRC support =20 @@ -233,3 +259,11 @@ words, it is the value of the ``in_voltageY_sampling_f= requency`` attribute divided by the number of enabled channels. So if 4 channels are enabled, w= ith the ``in_voltageY_sampling_frequency`` attributes set to 1 MHz, the effect= ive sample rate is 250 kHz. + +With oversampling enabled, the effective sample rate also depends on the O= SR +assigned to each channel. For example, if one of the 4 channels mentioned = in the +previous case is configured with an OSR of 4, the effective sample rate fo= r that +channel becomes (1 MHz / 4 ) =3D 250 kHz. The effective sample rate for all +four channels is then 1 / ( (3 / 1 MHz) + ( 1 / 250 kHz) ) ~=3D 142.9 kHz.= Note +that in this case "sample" refers to one read of all enabled channels (i.e= . one +full cycle through the auto-sequencer). --=20 2.39.5