From nobody Thu Dec 18 08:12:14 2025 Received: from mail-qv1-f51.google.com (mail-qv1-f51.google.com [209.85.219.51]) (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 96DED18FC80 for ; Thu, 9 Jan 2025 18:47:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736448452; cv=none; b=Gp5nmuRQ3L3IMjpGXRtWHh8dSfkz8fyOyTGEYx9NpZfutNCE7p97yzULekq4s313HxPXHfrKvjNKi/aEd6htRUlxQA2lN2dwy+nMTbUFlubG0S45R+sw67q8RG04vU1Y8jSWbNMOhC9dqICVSnj0ZsOryiswsX9C2cZII7VxXn4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736448452; c=relaxed/simple; bh=QmH0Jc72rrT2gr4U8hmdsQYBPxGKHbyfRYPHUZgVFqs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TCGCSBDNcVH9o1IOVUU0QviCggSTDBAA79XCXjjxFT9QM1OEpD1+IWbZCk/Bv3zZm5SPKqWTkn3Cj+RcMyvs1nk9bzroLjgdniVFx1e6aUmgzAHOjnXAQVxaRtO0zzVg8ZUq7JUOo3alS/hptX00NeTGssRLN5TZhAuy2FwcHW8= 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=Bkw3mPu0; arc=none smtp.client-ip=209.85.219.51 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="Bkw3mPu0" Received: by mail-qv1-f51.google.com with SMTP id 6a1803df08f44-6d91653e9d7so10750356d6.1 for ; Thu, 09 Jan 2025 10:47:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1736448449; x=1737053249; 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=I4KWrfzRSS8QmcuEP2dOjMn5pYIFnCrNTWoZpvWG0b0=; b=Bkw3mPu01dur6twEZ9zS9DPq6wi9edgpi5MI1HyJbmjOSimjSwIylzO3WsVkrMGf8/ vV1u4kLwryAyzjp6ZL9f9b4x0eJzfT+8loxMCdXxU7ByMnN3EYryiqO5DfzM82jRyVPe sh5xpkrh0EpZ+N+Nh3wxjGChoDgaxdAQRkfgCczTC+XhP/HnLvTAwk6gMeHJBlV2ItbI pJzsfTP0jqNgSqZG3JA3pv7/ed3ad8fGpGT/YCH1sBisihYBQQ1f4LFFp9O2+vdVXYcI sFYJTREESTgCFhH8FTxZMlYh8ESs88mUMP6BJF2jKnji0gRUaSFjSdylorO9Sj18pJVq t9JA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736448449; x=1737053249; 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=I4KWrfzRSS8QmcuEP2dOjMn5pYIFnCrNTWoZpvWG0b0=; b=ae97YX9teIhkCKSHMDC1PT0bYc5R01PE0OcsC8BABqXSZZcambKNqgCF4bOOda7bcQ 4aSLSOpe5a2mmdvClLE27ev9ZbdcbcUUAtmTN8kjhXhFFYsRt1YpNVqgEjKaIb7XBbi0 fezmme4J+Q/Ubx2ARWJcYoWf4BsgqWbrPXbgMMoV6yHXgaebB2E8x2m5gVT1eBHKTyPo FAUip2EC0a/7UK3H+zIfNOviJTW8Khqx33U/Li+mAL4f0kepVB+W2S4CLbyjFHQsOTH2 ojkeaQJbdxtP6a1qJXAExMLG3OemZn3kKQQlBB21xta7PecbDoOZ0eyTZI5erLwYFuqG vsIg== X-Forwarded-Encrypted: i=1; AJvYcCWyjowf6MJ3L/OlqnQAXVlcG/ZsOYlLEidftoMKHN1kzKEpVrVjru1LQQ1zUIxfsEfvrfqm2qk3fAURFeM=@vger.kernel.org X-Gm-Message-State: AOJu0Ywlzq/cDPQLaNEd7lSONqWkWDqANHsTycAlLn6AHjwl/3cvi2AZ zYIcKjTIOse56qsySO70T4qJYVgPlt1+wSuUPa2qOglymiAhkKVvQBhEbsaN6Vk= X-Gm-Gg: ASbGncsWW7O6w0OzSuXKxzQAYU3BkFS4pSO8MpxWeVD52hddjhQWl7m0zsHeBBVTeDQ RePDObtqlz78B2SzhXtlit2lgXhpoX25qONN4opCeh6xgbjBohlNC0APBCOJszPY1RJbxZqXqBc 46AwwmJ85+72S9lvfxhO3WYiE+ObC2+6oRgLAMY6WayR/wM+2JcmrWmm6RJs59tsouCvJAbvnIE vYPNB5MAfl+VnLooF3F9r20tqZWpvN0clrUlbDM2a4ED+TnA2vKb4K046WaLBdm/Lyc2BKh26gs gGLI6kWdUBnMjcn4 X-Google-Smtp-Source: AGHT+IFkFyuADZbI3PqrkCFeUDbWGNEMMmwFHP8Y+Tm72cLSBIcumS6DBEJQQEH2hMfwS4zT11E+7w== X-Received: by 2002:ad4:5d61:0:b0:6d8:916b:1caa with SMTP id 6a1803df08f44-6df9b254201mr132489596d6.27.1736448449401; Thu, 09 Jan 2025 10:47:29 -0800 (PST) Received: from localhost (d24-150-219-207.home.cgocable.net. [24.150.219.207]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6dfade72af8sm1062836d6.75.2025.01.09.10.47.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jan 2025 10:47:27 -0800 (PST) From: Trevor Gamblin Date: Thu, 09 Jan 2025 13:47:23 -0500 Subject: [PATCH v2 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: <20250109-ad4695-oversampling-v2-1-a46ac487082c@baylibre.com> References: <20250109-ad4695-oversampling-v2-0-a46ac487082c@baylibre.com> In-Reply-To: <20250109-ad4695-oversampling-v2-0-a46ac487082c@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 Reviewed-by: Nuno Sa Tested-by: David Lechner --- drivers/iio/adc/ad4695.c | 333 ++++++++++++++++++++++++++++++++++++++++++-= ---- 1 file changed, 303 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c index c8cd73d19e86..0caaeaa310ed 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,69 @@ 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) +{ + int val_calc, scale; + + switch (osr) { + case 4: + scale =3D 4; + break; + case 16: + scale =3D 2; + break; + case 64: + scale =3D 1; + break; + default: + scale =3D 8; + break; + } + + val =3D clamp_t(int, val, S32_MIN / 8, S32_MAX / 8); + + /* val2 range is (-MICRO, MICRO) if val =3D=3D 0, otherwise [0, MICRO) */ + if (val < 0) + val_calc =3D val * scale - val2 * scale / MICRO; + else if (val2 < 0) + /* if val2 < 0 then val =3D=3D 0 */ + val_calc =3D val2 * scale / (int)MICRO; + else + val_calc =3D val * scale + val2 * scale / MICRO; + + val_calc /=3D 2; + + return clamp_t(int, val_calc, S16_MIN, S16_MAX); +} + 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 +1285,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 +1294,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 +1327,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 +1375,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 +1438,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 +1466,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 +1490,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 +1661,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 +1712,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 +1728,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 08:12:15 2025 Received: from mail-qk1-f169.google.com (mail-qk1-f169.google.com [209.85.222.169]) (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 64BBE1A9B45 for ; Thu, 9 Jan 2025 18:47:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736448455; cv=none; b=IMJmImdeRE5OyW7T5MoRNFDVpc/OrszIw/rnjvzTPuJiGJTChF1WONoaS3E1wmY2vLH9ZXU17reKlRP/+ZL9PBMZLETv3Zffq66JjlqT5H0lM0S9jny8QrUJihD2tt+tbiLHB97xF8RecsO+jrpm/vY6pn0+A2Ip1t/Zwhqk0fg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736448455; c=relaxed/simple; bh=Ma8HaBPEK9LBfvT3QeN1X7ugzAmaSGzcmCUpk/9AAyw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nZpn/TgTbyXsm0hQjoUFtKk+aye8uCbUzpLt1WGYQiMV01PHLLT7s/N1fMNak6Gx2BtVq2b1QbEcght/Ipr6pVzqpYHTrlbdt6FMe0Qc2X9zcyoYwZFWsl8cG9bOaztybTbqCibeB7eAYmTuYHYt6wCFyh2qGteGpIv/pv6O2Jg= 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=LlkJ8fE1; arc=none smtp.client-ip=209.85.222.169 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="LlkJ8fE1" Received: by mail-qk1-f169.google.com with SMTP id af79cd13be357-7b6e4d38185so109275785a.0 for ; Thu, 09 Jan 2025 10:47:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1736448452; x=1737053252; 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=LlkJ8fE1zrlltokdVNr5foQV0Ck7gsEGj7hcGkEC+vbDdpIc+sSoOteXFWubmVm/2m Nlj3CXnaRIaUzuorQLS1TwGXF0p7tSSwlqeG1BTijqe8+EO3vB/PW6rdHIa7+hKHUSte nUpSgRT4ZLncIVLHM3tf9om6hlvhYjcCI9CohNhfUVio9JSLQCLyjBd+HlQfEpcKU2YO cH2tvDZi+Pm8daKuF9bQ0jrBMK0OQUNAX0A5KjWhX6I2Rcywo5Lc4IK+WM4M2cnIiiE5 xxaQ70DWmCIBn6syOnMipxRwA7i2TXNgCwbK8F+/ERSRbrXKgHXh/OkkBvI1FcubywqU 5Pmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736448452; x=1737053252; 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=n3kvqrpQ1HqBEbBE4WxrbV5CCgxKqRBlDfzxifL3cja2j57Mc3IT+a/hTLgl+w8jBL J8z04arPLPS5jzvWvo/YpeaAIG8I56Tj/8TnvniL7IT2815gIUzHuVoJwHTc0LKyyPAn vcia9F2fg3eclJn70bw0aU2GuH51G1175eAmhrqcx6PuTUqJUTXWasrKYy0+hE8p7jjn KJYqUt8N12Kkr9y7UxrtfrtZ0Evtq2a9R/InSU15bMoqmWp+sR3SC+Yk2CJMFRy9QUIn nK1GiPbIuovk6M6jbd3mbwVvjlCSKIxbD4sJRyxSsjsNZdFOhp13Pc8MwFnHik9eryx0 r8eg== X-Forwarded-Encrypted: i=1; AJvYcCWLvrzmJOiRGA2Lsc7rwzNxd6oXWzB2WTX9BlJvlxPumR/vI7K/XqXhw7IXyUD1fTk9xL5CDbAqw58ZVYQ=@vger.kernel.org X-Gm-Message-State: AOJu0YzMhMoOjSN98ngpJsMAA5x1zpTCm4OXlv3lxyQ8LgEeyZ+Eh3zR dC+OovA+DqV/RUq2R5TdGFTJmLH2kyN83LdC3UGPbgGMGpaz1GD4eIWfwV6CxtA= X-Gm-Gg: ASbGncueKmZSAFC6kLbmp7BRNKKxYM6AzKjCNXyI+QsT09RTNVRAPPIYanLk9aQTz5b eTMNHq1kFxV+R5eq+l8xzQrISmPevsGDSIIDPB8T+ez/CD5HE7pdqBX4Yf7QBlV8fPnsahLj5gB qIdW7w3BeBo0WB9Aw3WKyJVGmqOmYi13eyx9gJLnLcuMPq6hk9wVQphL5tAw7k8p6L4WpDmn0+c QNGSLyhQFPIAHY0qvnkgqVdCkVZNkEgttcdPQvs+rCHm5UrAOcQLR63tG8Krm5OL1ntuhmsmbEl BZV7P3kffVzMVIjl X-Google-Smtp-Source: AGHT+IGSh0OJ2ICJcgUrCCwD1CmO6Yk4iQVFhsuyeLSR7nuNJe3mJA1AXgnAS5hrWhV6frPSVt2d0w== X-Received: by 2002:a05:620a:4102:b0:7b6:d383:3cca with SMTP id af79cd13be357-7bcd9716e59mr1230536985a.35.1736448452291; Thu, 09 Jan 2025 10: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 af79cd13be357-7bce3248945sm94309785a.42.2025.01.09.10.47.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jan 2025 10:47:31 -0800 (PST) From: Trevor Gamblin Date: Thu, 09 Jan 2025 13:47:24 -0500 Subject: [PATCH v2 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: <20250109-ad4695-oversampling-v2-2-a46ac487082c@baylibre.com> References: <20250109-ad4695-oversampling-v2-0-a46ac487082c@baylibre.com> In-Reply-To: <20250109-ad4695-oversampling-v2-0-a46ac487082c@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 Tested-by: David Lechner --- 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