From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (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 CE963212FB0; Sat, 10 May 2025 22:44:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917081; cv=none; b=lB0bkIPC48FLt7feCYE96qTjO+MdNlWBt8fOLhgZVS4/iaD0fUg4kQGkQYhEfdUww/+psnS9WJckzE/7TwQZQRhBS62hzxj3pb+Vi8NHzlOSwqNOoEyicGparan+bDgWV+bwUah+NruGDX3Mp8fR0yeby3Ro1Z0aJM/cED+i4LI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917081; c=relaxed/simple; bh=pHpPP/AAF2ZJnFibnFDEHJ3e1IW13uLT58acUXO49WQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=V4qpenkMIjna3uOweZ2NXMFakZiVkxQ9vhnSKnz9fEKmcV5ZnvmG+PitND5nnv28HsfVUwh93LFyU8wruTVqtyHTMH3Lg2DSLlq0s11+XKwWyF72BBWngwZOR8j/19+nnnT64ofcj2TbHoL15Y2Ptmvd5T5GKrqZNgwB46IArVc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=X74CRg6O; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="X74CRg6O" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-43d72b749dcso3839235e9.1; Sat, 10 May 2025 15:44:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917078; x=1747521878; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=DIqO0nvCoKmouswT3ks4gDpudOxCgK+0lldLLrbYLPE=; b=X74CRg6OrqtV+kbIVpDE3zud91l6bbkPF9gtOPSuluofzXndcuTgBWOGx1u9EPpxub C8LWD8KO2bjq5QHVYUUPOMlCL+KSl64wKnGyqbmcmgY2fGSym86UyK4nfz9xikraoSN2 nl8bcHZAD/Kr+0PDqse6lmVAWCl0vUoBxuKxvR44STBNVpebl36pJTI5fR85V18ag/Qf gVZlApe5KFcsZAH0FKDGCf7hZaMyv4+HsdjHy13Xat8tksSi82UIfnnNRFl95GAc1F/Y TJW/U1Jfd1t0WWUrdEwnoqdusgpM83S+NfifNqEpoEiYitXScsJkmSG8Di3OvxAIOO6G Ar0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917078; x=1747521878; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DIqO0nvCoKmouswT3ks4gDpudOxCgK+0lldLLrbYLPE=; b=Yd9KxFjjzY5XNg/HdF8uTkNLIi91nAWXuVrn6+jH+MbD1j0uNIxyQN1PhJwPeLmKhh UjI5CtHRr4rY5we3lMSciyhqceG0vq6GVux2dLfuxb9qMSZ8Lj5SFo6/RjyTmFtMNtlR J83HAY/0UwUMuyKL9OOQLbV9E2EqGchKijtpUGMjko3zVxFXoHI/utzFZ+oWPAVtl7j6 So3Vodw9mImogyLVrwxPN+QvvQHY0gIqRmxPrW4NQGVbD3270q2DA73qEbWzZmha/39b XDhyzww6p4qybk4NlBrQJJ3JIOLmfTdQsYXdzmJ1jB6KyoZzMaMSwGUH9VVse5Iq7Jar WQKA== X-Forwarded-Encrypted: i=1; AJvYcCUS3dHeAFbOsMhOl3uHtWLMW0NBvmHG1Zyya1X7I5TwVZ8YBDJncBNUrBzFUNnK63oSQxNymL0NfyXm5w0=@vger.kernel.org X-Gm-Message-State: AOJu0Yx7UcnLvCOO0CjVEc9iRDGaK0/pTF+Qg/dFNF+VUYz8vDUmCmJF luiMxQBQmpdRkXQKBPW5aQ4iHZ60uKsIfMiCDiaA5iBwpTX55Oue X-Gm-Gg: ASbGnctlrFSE8lcEEb4PQSVjY8/leNP5ZzsqRO82riYpDx2VC/GMQv+sOm7xqpiBU2w JXVe55ebkuqmL72xrIX4H4PbeBlf0fUkxSWo1LZJH03bd2PKUzixdQAGNAgVWRPzzc8bdjSA/gx j7W89IK4ACyF3zLg5Few8x/PdZqBaHudV4LySBzFFZ18mlmqz8wAHVGVXNOUzOTGPT+YSCfZne/ iVADQgHNekoDXWImbHdlewNOVeiUla9qpSEMeSF7sKh0Mrct5H16Vuj1ck2GeHuMoV54K4JW3kJ DkGuWN1UaglZMPGNYWQKTm1P5TCDatgobUr1/c9IsIGPy/tYPVY1BjJvRLdrOyXyoFjK8uD+/M9 f9mYSUix7kF9ElEbcqj4K7A== X-Google-Smtp-Source: AGHT+IHhH4kcGqYt31UC3pP6Z93GHyZ4oNNc8k+nZWObK1c9DshfUZL6xAgGKi+T6otxhBJw3Qad2g== X-Received: by 2002:a5d:64cd:0:b0:3a0:9188:ef58 with SMTP id ffacd0b85a97d-3a1f64ab2e7mr2473442f8f.14.1746917077834; Sat, 10 May 2025 15:44:37 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:37 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 1/7] iio: accel: adxl345: extend sample frequency adjustments Date: Sat, 10 May 2025 22:43:59 +0000 Message-Id: <20250510224405.17910-2-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Introduce enums and functions to work with the sample frequency adjustments. Let the sample frequency adjust via IIO and configure a reasonable default. Replace the old static sample frequency handling. During adjustment of bw registers, measuring is disabled and afterwards enabled again. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345.h | 2 +- drivers/iio/accel/adxl345_core.c | 150 ++++++++++++++++++++++++------- 2 files changed, 118 insertions(+), 34 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 7d482dd595fa..6c1f96406136 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -69,7 +69,7 @@ * BW_RATE bits - Bandwidth and output data rate. The default value is * 0x0A, which translates to a 100 Hz output data rate */ -#define ADXL345_BW_RATE GENMASK(3, 0) +#define ADXL345_BW_RATE_MSK GENMASK(3, 0) #define ADXL345_BW_LOW_POWER BIT(4) #define ADXL345_BASE_RATE_NANO_HZ 97656250LL =20 diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index c464c87033fb..bbdc9d10d962 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -64,6 +64,45 @@ static const unsigned int adxl345_tap_time_reg[] =3D { [ADXL345_TAP_TIME_DUR] =3D ADXL345_REG_DUR, }; =20 +enum adxl345_odr { + ADXL345_ODR_0P10HZ =3D 0, + ADXL345_ODR_0P20HZ, + ADXL345_ODR_0P39HZ, + ADXL345_ODR_0P78HZ, + ADXL345_ODR_1P56HZ, + ADXL345_ODR_3P13HZ, + ADXL345_ODR_6P25HZ, + ADXL345_ODR_12P50HZ, + ADXL345_ODR_25HZ, + ADXL345_ODR_50HZ, + ADXL345_ODR_100HZ, + ADXL345_ODR_200HZ, + ADXL345_ODR_400HZ, + ADXL345_ODR_800HZ, + ADXL345_ODR_1600HZ, + ADXL345_ODR_3200HZ, +}; + +/* Certain features recommend 12.5 Hz - 400 Hz ODR */ +static const int adxl345_odr_tbl[][2] =3D { + [ADXL345_ODR_0P10HZ] =3D { 0, 97000 }, + [ADXL345_ODR_0P20HZ] =3D { 0, 195000 }, + [ADXL345_ODR_0P39HZ] =3D { 0, 390000 }, + [ADXL345_ODR_0P78HZ] =3D { 0, 781000 }, + [ADXL345_ODR_1P56HZ] =3D { 1, 562000 }, + [ADXL345_ODR_3P13HZ] =3D { 3, 125000 }, + [ADXL345_ODR_6P25HZ] =3D { 6, 250000 }, + [ADXL345_ODR_12P50HZ] =3D { 12, 500000 }, + [ADXL345_ODR_25HZ] =3D { 25, 0 }, + [ADXL345_ODR_50HZ] =3D { 50, 0 }, + [ADXL345_ODR_100HZ] =3D { 100, 0 }, + [ADXL345_ODR_200HZ] =3D { 200, 0 }, + [ADXL345_ODR_400HZ] =3D { 400, 0 }, + [ADXL345_ODR_800HZ] =3D { 800, 0 }, + [ADXL345_ODR_1600HZ] =3D { 1600, 0 }, + [ADXL345_ODR_3200HZ] =3D { 3200, 0 }, +}; + struct adxl345_state { const struct adxl345_chip_info *info; struct regmap *regmap; @@ -107,6 +146,7 @@ static struct iio_event_spec adxl345_events[] =3D { BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index =3D (index), \ .scan_type =3D { \ .sign =3D 's', \ @@ -383,14 +423,53 @@ static int adxl345_set_tap_latent(struct adxl345_stat= e *st, u32 val_int, return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us); } =20 +static int adxl345_find_odr(struct adxl345_state *st, int val, + int val2, enum adxl345_odr *odr) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(adxl345_odr_tbl); i++) { + if (val =3D=3D adxl345_odr_tbl[i][0] && + val2 =3D=3D adxl345_odr_tbl[i][1]) { + *odr =3D i; + return 0; + } + } + + return -EINVAL; +} + +static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr) +{ + return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, + ADXL345_BW_RATE_MSK, + FIELD_PREP(ADXL345_BW_RATE_MSK, odr)); +} + +static int adxl345_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals =3D (int *)adxl345_odr_tbl; + *type =3D IIO_VAL_INT_PLUS_MICRO; + *length =3D ARRAY_SIZE(adxl345_odr_tbl) * 2; + return IIO_AVAIL_LIST; + } + + return -EINVAL; +} + static int adxl345_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct adxl345_state *st =3D iio_priv(indio_dev); __le16 accel; - long long samp_freq_nhz; unsigned int regval; + enum adxl345_odr odr; int ret; =20 switch (mask) { @@ -428,12 +507,10 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, ret =3D regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); if (ret) return ret; - - samp_freq_nhz =3D ADXL345_BASE_RATE_NANO_HZ << - (regval & ADXL345_BW_RATE); - *val =3D div_s64_rem(samp_freq_nhz, NANOHZ_PER_HZ, val2); - - return IIO_VAL_INT_PLUS_NANO; + odr =3D FIELD_GET(ADXL345_BW_RATE_MSK, regval); + *val =3D adxl345_odr_tbl[odr][0]; + *val2 =3D adxl345_odr_tbl[odr][1]; + return IIO_VAL_INT_PLUS_MICRO; } =20 return -EINVAL; @@ -444,7 +521,12 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct adxl345_state *st =3D iio_priv(indio_dev); - s64 n; + enum adxl345_odr odr; + int ret; + + ret =3D adxl345_set_measure_en(st, false); + if (ret) + return ret; =20 switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: @@ -452,20 +534,26 @@ static int adxl345_write_raw(struct iio_dev *indio_de= v, * 8-bit resolution at +/- 2g, that is 4x accel data scale * factor */ - return regmap_write(st->regmap, - ADXL345_REG_OFS_AXIS(chan->address), - val / 4); + ret =3D regmap_write(st->regmap, + ADXL345_REG_OFS_AXIS(chan->address), + val / 4); + if (ret) + return ret; + break; case IIO_CHAN_INFO_SAMP_FREQ: - n =3D div_s64(val * NANOHZ_PER_HZ + val2, - ADXL345_BASE_RATE_NANO_HZ); + ret =3D adxl345_find_odr(st, val, val2, &odr); + if (ret) + return ret; =20 - return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, - ADXL345_BW_RATE, - clamp_val(ilog2(n), 0, - ADXL345_BW_RATE)); + ret =3D adxl345_set_odr(st, odr); + if (ret) + return ret; + break; + default: + return -EINVAL; } =20 - return -EINVAL; + return adxl345_set_measure_en(st, true); } =20 static int adxl345_read_event_config(struct iio_dev *indio_dev, @@ -654,7 +742,7 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *in= dio_dev, case IIO_CHAN_INFO_CALIBBIAS: return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - return IIO_VAL_INT_PLUS_NANO; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -667,19 +755,6 @@ static void adxl345_powerdown(void *ptr) adxl345_set_measure_en(st, false); } =20 -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( -"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 20= 0 400 800 1600 3200" -); - -static struct attribute *adxl345_attrs[] =3D { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL -}; - -static const struct attribute_group adxl345_attrs_group =3D { - .attrs =3D adxl345_attrs, -}; - static int adxl345_set_fifo(struct adxl345_state *st) { unsigned int intio; @@ -931,9 +1006,9 @@ static irqreturn_t adxl345_irq_handler(int irq, void *= p) } =20 static const struct iio_info adxl345_info =3D { - .attrs =3D &adxl345_attrs_group, .read_raw =3D adxl345_read_raw, .write_raw =3D adxl345_write_raw, + .read_avail =3D adxl345_read_avail, .write_raw_get_fmt =3D adxl345_write_raw_get_fmt, .read_event_config =3D adxl345_read_event_config, .write_event_config =3D adxl345_write_event_config, @@ -999,6 +1074,15 @@ int adxl345_core_probe(struct device *dev, struct reg= map *regmap, indio_dev->num_channels =3D ARRAY_SIZE(adxl345_channels); indio_dev->available_scan_masks =3D adxl345_scan_masks; =20 + /* + * Using I2C at 100kHz would limit the maximum ODR to 200Hz, operation + * at an output rate above the recommended maximum may result in + * undesired behavior. + */ + ret =3D adxl345_set_odr(st, ADXL345_ODR_200HZ); + if (ret) + return ret; + /* Reset interrupts at start up */ ret =3D regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00); if (ret) --=20 2.39.5 From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (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 D104C2144C7; Sat, 10 May 2025 22:44:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917083; cv=none; b=miaHmxwvd1CStIamuJ2GqAOE8e3Pp0+HnYT73hNFkjHzHvGat3C/AuV7PL+6p1hXR5AHiqe0hTGSh+L9Zwh0igNag0V/qciJcDuEXerBKpqxRDDtDZ2HlU/Cl71RjlWBwBKfe3nKwne52QNMms4f75nsJ37tmsbwf1KlRCV2klk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917083; c=relaxed/simple; bh=nD3kMmYbQmRIukyhs5O2pJl0UAXAPycvgRVQ22eP+sk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=k1cfAla0nMcdSmysbX6FDec3E00CiNotc6dOp1aEUrYqT+ZaQrWLLwDPgrtRVz/NBpj9syBNH4ZBwWfWeRqrw9yHl3T+K4KRNhhb3fWL5Iw3yuXHoJDLR1TlcPKKUAvqQ0M17uAnJk+lKPJTYO8LwKnOnDbLbFJr7cpNlMf1O1A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FK8p8nZU; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FK8p8nZU" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-3a0bcb1f1afso410742f8f.0; Sat, 10 May 2025 15:44:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917080; x=1747521880; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0ZLhZirtRkSbpqjTR8RiHx2rLb1iz9QcvFtV8hE/w7A=; b=FK8p8nZUZIVduWeirPSPn+xxATtPZnILHBL7uMWgNTQdgVBitgZDtMq7J7WyvqV/F6 GXQ2GeIOS5bkixxLgCdPl57zHCeY7PbiDteENx+v8TavORkMv4BtVJAR4TXN7W1arzg+ /dMIaDQxDemDrE83u9oKHRMsYzAlmvHd0oGQs31lJpjMn7HGUyM5ci2dlOi67G7k64Ub g5sHdKyDBSVqXPvs2Q2bd5c658UoBnpg+giccqUETM0QtelOal9j8L9KlmbfzazUr3We EdkuBIIGABuYgDpJbVZnRMSo4miyJMcGo4g9WINjZLLuIo+Pch/7Sj5rcw2gnV3BU5BC TEmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917080; x=1747521880; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0ZLhZirtRkSbpqjTR8RiHx2rLb1iz9QcvFtV8hE/w7A=; b=hIU0veTSJ6WZCH25/7To3M/dfIyU9DcFGkbcjbMNtuUkPj+Jwuo+qT9AC7dxVX0Zkw lI3JRwIMO+/X1JFKq5ZeqnCjd4FEX+nDDcalVvTsXDs6yQUsvdb4qFIB/49Ygz/tpV+/ YcFGzeG+gqTFb3wfjdSS3wygwZot151ChFwr6oqk+cpTjdIqqDduBLvjwOZzfj95wqgQ FyCmotR+lTovSj1BU5E4Ux/FzoIP8woqa2r/H0SeVC00/FwYe5aaO+1xI8QyNFl5MwhN qjoM/k99Ec005qTbIzNJkCM5oZHRFW2HKKD58Ac4A66xjlq06iDdlgbwAJAR3uhsj1zo uNmQ== X-Forwarded-Encrypted: i=1; AJvYcCWph+upH8ku3tcSiqZxnNilrR7aa4CMaDlfn7uZsXmVlc0XYv6Zgz5JGkr4XYYu0KD3/6YtdDQv7Yzzmj4=@vger.kernel.org X-Gm-Message-State: AOJu0YygmAdbir15tusPtP1gshbHSnMq+3xGYCpaUPEVnfPEX+V9hhsk K4c13aDA20dIvBmfuNWHOAY8IYtJyePQ9znv7rOoFiqrEFImoDiJ X-Gm-Gg: ASbGnctjPALlHr3Ix3AlgH/QEEdHomHmGNmRVV2yMv8Zis9uE6Xe2dvp64ggGC6A0NK H+9lngcFFwQNE7V3J4wO7ZrczDC/7est8snBTZdlw6KFbUomrC9f1F89nSYBssqRIPxPEJIMt5U UTyIP6thQDLNH78Y+xXIIp833uKjFL9KwMaZEpu8fPnAS8no/xQF96UYzDFo4Rnlw/KTrRe8Ake jOGzaepl4pxODtvzAYPMGkWTazLOx9BGaxL6uQ0HAIgEjZyWCHLXV+X5o+bUXgPBlUheJVPdpjt uwfda/EC12toEmpg94LBm9gSdfJv4D8LxXqz3QSYYMVQWtfJVQjRJz+1DZElaWZK9OsIr0hFyq8 VM/LyG6YsF2/NpoMhRGFmuw== X-Google-Smtp-Source: AGHT+IF34pL4GhZChggXGyxnA/TdYhJ9WaZyL0Tts5Hz/cE+MR3XtQEN5CqxBjHFuLjB93hbF62hPQ== X-Received: by 2002:a5d:5f91:0:b0:39c:30d9:48 with SMTP id ffacd0b85a97d-3a1f643c674mr2408202f8f.6.1746917079472; Sat, 10 May 2025 15:44:39 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:38 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 2/7] iio: accel: adxl345: add g-range configuration Date: Sat, 10 May 2025 22:44:00 +0000 Message-Id: <20250510224405.17910-3-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Introduce a mechanism to be able to configure and work with the available g-ranges keeping the precision of 13 digits. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 82 ++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index bbdc9d10d962..7c093c0241de 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -83,6 +83,13 @@ enum adxl345_odr { ADXL345_ODR_3200HZ, }; =20 +enum adxl345_range { + ADXL345_2G_RANGE =3D 0, + ADXL345_4G_RANGE, + ADXL345_8G_RANGE, + ADXL345_16G_RANGE, +}; + /* Certain features recommend 12.5 Hz - 400 Hz ODR */ static const int adxl345_odr_tbl[][2] =3D { [ADXL345_ODR_0P10HZ] =3D { 0, 97000 }, @@ -103,6 +110,25 @@ static const int adxl345_odr_tbl[][2] =3D { [ADXL345_ODR_3200HZ] =3D { 3200, 0 }, }; =20 +/* + * Full resolution frequency table: + * (g * 2 * 9.80665) / (2^(resolution) - 1) + * + * resolution :=3D 13 (full) + * g :=3D 2|4|8|16 + * + * 2g at 13bit: 0.004789 + * 4g at 13bit: 0.009578 + * 8g at 13bit: 0.019156 + * 16g at 16bit: 0.038312 + */ +static const int adxl345_fullres_range_tbl[][2] =3D { + [ADXL345_2G_RANGE] =3D { 0, 4789 }, + [ADXL345_4G_RANGE] =3D { 0, 9578 }, + [ADXL345_8G_RANGE] =3D { 0, 19156 }, + [ADXL345_16G_RANGE] =3D { 0, 38312 }, +}; + struct adxl345_state { const struct adxl345_chip_info *info; struct regmap *regmap; @@ -146,7 +172,8 @@ static struct iio_event_spec adxl345_events[] =3D { BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ - .info_mask_shared_by_type_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available =3D BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index =3D (index), \ .scan_type =3D { \ .sign =3D 's', \ @@ -446,12 +473,40 @@ static int adxl345_set_odr(struct adxl345_state *st, = enum adxl345_odr odr) FIELD_PREP(ADXL345_BW_RATE_MSK, odr)); } =20 +static int adxl345_find_range(struct adxl345_state *st, int val, int val2, + enum adxl345_range *range) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(adxl345_fullres_range_tbl); i++) { + if (val =3D=3D adxl345_fullres_range_tbl[i][0] && + val2 =3D=3D adxl345_fullres_range_tbl[i][1]) { + *range =3D i; + return 0; + } + } + + return -EINVAL; +} + +static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range = range) +{ + return regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, + ADXL345_DATA_FORMAT_RANGE, + FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range)); +} + static int adxl345_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) { switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals =3D (int *)adxl345_fullres_range_tbl; + *type =3D IIO_VAL_INT_PLUS_MICRO; + *length =3D ARRAY_SIZE(adxl345_fullres_range_tbl) * 2; + return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SAMP_FREQ: *vals =3D (int *)adxl345_odr_tbl; *type =3D IIO_VAL_INT_PLUS_MICRO; @@ -470,6 +525,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, __le16 accel; unsigned int regval; enum adxl345_odr odr; + enum adxl345_range range; int ret; =20 switch (mask) { @@ -488,8 +544,12 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, *val =3D sign_extend32(le16_to_cpu(accel), 12); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val =3D 0; - *val2 =3D st->info->uscale; + ret =3D regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, ®val); + if (ret) + return ret; + range =3D FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval); + *val =3D adxl345_fullres_range_tbl[range][0]; + *val2 =3D adxl345_fullres_range_tbl[range][1]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: ret =3D regmap_read(st->regmap, @@ -521,6 +581,7 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct adxl345_state *st =3D iio_priv(indio_dev); + enum adxl345_range range; enum adxl345_odr odr; int ret; =20 @@ -549,6 +610,15 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, if (ret) return ret; break; + case IIO_CHAN_INFO_SCALE: + ret =3D adxl345_find_range(st, val, val2, &range); + if (ret) + return ret; + + ret =3D adxl345_set_range(st, range); + if (ret) + return ret; + break; default: return -EINVAL; } @@ -741,6 +811,8 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *in= dio_dev, switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: return IIO_VAL_INT_PLUS_MICRO; default: @@ -1083,6 +1155,10 @@ int adxl345_core_probe(struct device *dev, struct re= gmap *regmap, if (ret) return ret; =20 + ret =3D adxl345_set_range(st, ADXL345_16G_RANGE); + if (ret) + return ret; + /* Reset interrupts at start up */ ret =3D regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00); if (ret) --=20 2.39.5 From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.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 E846D217719; Sat, 10 May 2025 22:44:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917085; cv=none; b=Ui5Kq2E35VsEWwaaYtY13+uHU8x+p9RgU5jrJ9/QNMqlhVByrzLs6zIk4Vayd/7hbZg2gIGhmrvu1ow/5BhH0d38jAIeZJXH0crBmCPilp0e6PYrDAYAL+7msbgDL7ZU/agODE8xWpkZGcG43UtzMRo/cBqhOSQ37FQX/+h0QBg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917085; c=relaxed/simple; bh=8KQC0TWXqIvCCF6ajMwFgZWvFYTt/EXi+/lxbNKX7Y4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Nm4lVlK+csiSywKTZAgZcUkC53dUZtWC/G6DOEhpmwXjqFtib5eZwRogx5qHEXTtAUpr/nLGdmm0tVuXxibwGAwTGzo9FmOW/0NCzDPPFmRkJ4bM8ptOCo82K55nNzfeIDC8qz3OBDHt/7ZZTx92U+fRSGAqpGmPFGKb1Ii5cRs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=T0Ji0dII; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="T0Ji0dII" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-43cfe99f2a7so4013355e9.2; Sat, 10 May 2025 15:44:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917081; x=1747521881; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=t9lGv3RpTEO+CVygRuJVfKXfD/b84o8z4MvMG3CkyMU=; b=T0Ji0dIIQSa8P4YYtX/dRoe0TITnS1ytH+e75WImyxCZ2cM/ot8SFXmgycNEnoAh3v /3wrai4rQLGxKgJ1bwyJ9EOhQVFo1sm7nmOZ4pRJWxx0jDNIYLrwVckZXserFKK5Od9X nmUNAlw8b6C1aoKEjAVESP0mVRFVW7Ot9ONsQQir/nOjP7y9ngtlca1sy3I+p6rmqUj8 T6WX8ompy5WJVBJjkysiUgCiEsHYn6zuNYs5BG1prYuVSQXLrZ3uG0BZ+4bHhqViQU2J t3dvQ+0z8TbW3QDLKkiMtJmwawpNRluw27AFX2a+dwLKOybJ2t+mLgWiyHaL+5PvKv5z 3tFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917081; x=1747521881; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=t9lGv3RpTEO+CVygRuJVfKXfD/b84o8z4MvMG3CkyMU=; b=PNnqytKtYZGCMHvzeXlCDjApbNnoSHqigBEoDuWtrVP4spu8GlJDTgW3pi46CM+/Tr AlrT+uCHTXyS76N2HanUVJvojohbjCZdChw9jk5mpy3DB6L+DHjgZPPD9dt5vcey6dP8 lDDJBYg3L86GHsY80V31/y8tP7RDjMMIaoYHF180WRVtUji01iUlQiaAJShzNkxm0S0d MRxt/4jBGRV4rAqrC/h+WTedxVLZcvjtGrvDCi/jhs1oT/AuTGgoilkOGjmMjXTc4Ieh p3hQiIb4HCsMq49toFm9m2dfe3r9/ftnru6TMKzw1Sb2RI+gHnaCavOlqTOoynHjB6VS /Pyw== X-Forwarded-Encrypted: i=1; AJvYcCX6ykwyt7HYFGN9MLR0Yt0cuhi6b3yWp5wcmE/eKFQyszaTTe01efw9Iz4Vrdv1s9hHDWBRiNoGIEivd6Q=@vger.kernel.org X-Gm-Message-State: AOJu0Yx+ddQ36D2gn5/rHBRAdTs+z7KojDHCYm4l0lTfpjpDYgdh+LiA pFnBKckpjjSHzT+HNc/eTJ7l8ACH6xkkVFu9kJ9g8RHDGUt8H/DtXnLtU8Rb X-Gm-Gg: ASbGncuI0YbeY+nUQOH5jvbz+HjFmIpPnhUY+hg4iuScyZ8EYSRZJ5Es82VexUDxqix 65QlrNjuSo5YDFn18T+A2SZoC1Fz3hs4vV/wmwB0+pnA24ybftzIyic/MoIp1YWTJnFJ3BUFI9E OMSryzCiaPX2LbZ1ajAdMIpbPMIhK2IvzKJvQsWhFQwW7Wv1dstqeGowGUFY5dLjjPRyl5W/YfS BsuOmOXMdPfpzGFskyLouKsIaYbBTIuh9zMp8qVP4t8ZYc7awM25o2FUdWudnrB3o4nFO6o4Ha2 KuqI6COMrTwyFbwkLOZMUFpioKoBYfY25U9OwShZeUwOUoNS9tuWSWAovM+U3lHPugLA8I/VOVm O8mhUY97hWeuM/bHtWB8Zog== X-Google-Smtp-Source: AGHT+IF+o+cVHi/fvzp7TCXsNMKu4h6YRUWz7yM6FJ0YxJisWLRe1iKzVpvPsJYDY+1Uv1EIDmky4g== X-Received: by 2002:a5d:5f8f:0:b0:3a0:75ff:261f with SMTP id ffacd0b85a97d-3a1f6487679mr2088787f8f.11.1746917081204; Sat, 10 May 2025 15:44:41 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:40 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 3/7] iio: accel: adxl345: add activity event feature Date: Sat, 10 May 2025 22:44:01 +0000 Message-Id: <20250510224405.17910-4-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Make the sensor detect and issue interrupts at activity. Activity events are configured by a threshold stored in regmap cache. Initialize the activity threshold register to a reasonable default value in probe. The value is taken from the older ADXL345 input driver, to provide a similar behavior. Reset the activity/inactivity direction enabling register in probe. Reset and initialization shall bring the sensor in a defined initial state to prevent dangling settings when warm restarting the sensor. Activity, ODR configuration together with the range setting prepare the activity/inactivity hystersesis setup, implemented in a follow up patch. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 218 ++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index 7c093c0241de..32d014bd1e52 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -36,11 +36,16 @@ #define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0) #define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) #define ADXL345_REG_TAP_SUPPRESS BIT(3) +#define ADXL345_REG_ACT_AXIS_MSK GENMASK(6, 4) =20 #define ADXL345_TAP_Z_EN BIT(0) #define ADXL345_TAP_Y_EN BIT(1) #define ADXL345_TAP_X_EN BIT(2) =20 +#define ADXL345_ACT_Z_EN BIT(4) +#define ADXL345_ACT_Y_EN BIT(5) +#define ADXL345_ACT_X_EN BIT(6) + /* single/double tap */ enum adxl345_tap_type { ADXL345_SINGLE_TAP, @@ -64,6 +69,19 @@ static const unsigned int adxl345_tap_time_reg[] =3D { [ADXL345_TAP_TIME_DUR] =3D ADXL345_REG_DUR, }; =20 +/* activity/inactivity */ +enum adxl345_activity_type { + ADXL345_ACTIVITY, +}; + +static const unsigned int adxl345_act_int_reg[] =3D { + [ADXL345_ACTIVITY] =3D ADXL345_INT_ACTIVITY, +}; + +static const unsigned int adxl345_act_thresh_reg[] =3D { + [ADXL345_ACTIVITY] =3D ADXL345_REG_THRESH_ACT, +}; + enum adxl345_odr { ADXL345_ODR_0P10HZ =3D 0, ADXL345_ODR_0P20HZ, @@ -145,6 +163,13 @@ struct adxl345_state { }; =20 static struct iio_event_spec adxl345_events[] =3D { + { + /* activity */ + .type =3D IIO_EV_TYPE_MAG, + .dir =3D IIO_EV_DIR_RISING, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type =3D BIT(IIO_EV_INFO_VALUE), + }, { /* single tap */ .type =3D IIO_EV_TYPE_GESTURE, @@ -239,6 +264,99 @@ static int adxl345_set_measure_en(struct adxl345_state= *st, bool en) return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val); } =20 +/* act/inact */ + +static int adxl345_is_act_inact_en(struct adxl345_state *st, + enum iio_modifier axis, + enum adxl345_activity_type type, bool *en) +{ + unsigned int regval; + u32 axis_ctrl; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl); + if (ret) + return ret; + + if (type =3D=3D ADXL345_ACTIVITY) { + switch (axis) { + case IIO_MOD_X: + *en =3D FIELD_GET(ADXL345_ACT_X_EN, axis_ctrl); + break; + case IIO_MOD_Y: + *en =3D FIELD_GET(ADXL345_ACT_Y_EN, axis_ctrl); + break; + case IIO_MOD_Z: + *en =3D FIELD_GET(ADXL345_ACT_Z_EN, axis_ctrl); + break; + default: + *en =3D false; + return -EINVAL; + } + } + + if (*en) { + ret =3D regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val); + if (ret) + return ret; + + *en =3D adxl345_act_int_reg[type] & regval; + } + + return 0; +} + +static int adxl345_set_act_inact_en(struct adxl345_state *st, + enum iio_modifier axis, + enum adxl345_activity_type type, + bool cmd_en) +{ + bool en; + unsigned int threshold; + u32 axis_ctrl =3D 0; + int ret; + + if (type =3D=3D ADXL345_ACTIVITY) { + switch (axis) { + case IIO_MOD_X: + axis_ctrl =3D ADXL345_ACT_X_EN; + break; + case IIO_MOD_Y: + axis_ctrl =3D ADXL345_ACT_Y_EN; + break; + case IIO_MOD_Z: + axis_ctrl =3D ADXL345_ACT_Z_EN; + break; + default: + return -EINVAL; + } + } + + if (cmd_en) + ret =3D regmap_set_bits(st->regmap, + ADXL345_REG_ACT_INACT_CTRL, axis_ctrl); + else + ret =3D regmap_clear_bits(st->regmap, + ADXL345_REG_ACT_INACT_CTRL, axis_ctrl); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, adxl345_act_thresh_reg[type], &threshold); + if (ret) + return ret; + + en =3D false; + + if (type =3D=3D ADXL345_ACTIVITY) { + en =3D FIELD_GET(ADXL345_REG_ACT_AXIS_MSK, axis_ctrl) && + threshold; + } + + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + adxl345_act_int_reg[type], + en ? adxl345_act_int_reg[type] : 0); +} + /* tap */ =20 static int _adxl345_set_tap_int(struct adxl345_state *st, @@ -636,6 +754,18 @@ static int adxl345_read_event_config(struct iio_dev *i= ndio_dev, int ret; =20 switch (type) { + case IIO_EV_TYPE_MAG: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D adxl345_is_act_inact_en(st, chan->channel2, + ADXL345_ACTIVITY, + &int_en); + if (ret) + return ret; + return int_en; + default: + return -EINVAL; + } case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -667,6 +797,15 @@ static int adxl345_write_event_config(struct iio_dev *= indio_dev, struct adxl345_state *st =3D iio_priv(indio_dev); =20 switch (type) { + case IIO_EV_TYPE_MAG: + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl345_set_act_inact_en(st, chan->channel2, + ADXL345_ACTIVITY, + state); + default: + return -EINVAL; + } case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -689,10 +828,30 @@ static int adxl345_read_event_value(struct iio_dev *i= ndio_dev, int *val, int *val2) { struct adxl345_state *st =3D iio_priv(indio_dev); + unsigned int act_threshold; unsigned int tap_threshold; int ret; =20 switch (type) { + case IIO_EV_TYPE_MAG: + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_ACTIVITY], + &act_threshold); + if (ret) + return ret; + + *val =3D act_threshold; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -743,6 +902,25 @@ static int adxl345_write_event_value(struct iio_dev *i= ndio_dev, return ret; =20 switch (type) { + case IIO_EV_TYPE_MAG: + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_ACTIVITY], + val); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + break; case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -985,7 +1163,8 @@ static int adxl345_fifo_push(struct iio_dev *indio_dev, } =20 static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, - enum iio_modifier tap_dir) + enum iio_modifier tap_dir, + enum iio_modifier act_dir) { s64 ts =3D iio_get_time_ns(indio_dev); struct adxl345_state *st =3D iio_priv(indio_dev); @@ -1012,6 +1191,16 @@ static int adxl345_push_event(struct iio_dev *indio_= dev, int int_stat, return ret; } =20 + if (FIELD_GET(ADXL345_INT_ACTIVITY, int_stat)) { + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + ts); + if (ret) + return ret; + } + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { samples =3D adxl345_get_samples(st); if (samples < 0) @@ -1039,6 +1228,7 @@ static irqreturn_t adxl345_irq_handler(int irq, void = *p) struct adxl345_state *st =3D iio_priv(indio_dev); unsigned int regval; enum iio_modifier tap_dir =3D IIO_NO_MOD; + enum iio_modifier act_dir =3D IIO_NO_MOD; u32 axis_ctrl; int int_stat; int ret; @@ -1047,7 +1237,8 @@ static irqreturn_t adxl345_irq_handler(int irq, void = *p) if (ret) return IRQ_NONE; =20 - if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl)) { + if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) || + FIELD_GET(ADXL345_REG_ACT_AXIS_MSK, axis_ctrl)) { ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, ®val); if (ret) return IRQ_NONE; @@ -1058,12 +1249,19 @@ static irqreturn_t adxl345_irq_handler(int irq, voi= d *p) tap_dir =3D IIO_MOD_Y; else if (FIELD_GET(ADXL345_TAP_X_EN, regval)) tap_dir =3D IIO_MOD_X; + + if (FIELD_GET(ADXL345_ACT_Z_EN, regval)) + act_dir =3D IIO_MOD_Z; + else if (FIELD_GET(ADXL345_ACT_Y_EN, regval)) + act_dir =3D IIO_MOD_Y; + else if (FIELD_GET(ADXL345_ACT_X_EN, regval)) + act_dir =3D IIO_MOD_X; } =20 if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat)) return IRQ_NONE; =20 - if (adxl345_push_event(indio_dev, int_stat, tap_dir)) + if (adxl345_push_event(indio_dev, int_stat, tap_dir, act_dir)) goto err; =20 if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat)) @@ -1224,6 +1422,20 @@ int adxl345_core_probe(struct device *dev, struct re= gmap *regmap, if (ret) return ret; =20 + /* + * Initialization with reasonable values to simplify operation + * of the sensor. The default values are partly taken from the + * older input driver for the ADXL345, and partly based on + * recommendations in the datasheet. + */ + ret =3D regmap_write(st->regmap, ADXL345_REG_ACT_INACT_CTRL, 0); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6); + if (ret) + return ret; + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); if (ret) return ret; --=20 2.39.5 From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (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 AA1F721ABCC; Sat, 10 May 2025 22:44:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917086; cv=none; b=P+6tRS7j01usYWZgT2h4GFHsUMZPwBMxm+CefbhBSjXkMcv2IX8r/b8P/0u1gy4DspOS8eDoX8eGNp9dfUgqgK6kkBoI+IBeYy2zFMMF5/dV5ahGJKk9UVOJ7trSFT63qcPKN3LpuBM8YJGXdpl9/Hu7PPE0jEgqg7r3YK2t6AQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917086; c=relaxed/simple; bh=MOr4IvKGTgebHvHbJUV8wyvXIn/RXs57ZZld6zmaP8M=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=cXeyrDhgRfp7Pf7Lfw23p2gGwVmQTL77jgOSjO/2Lwte0aPk1+tiP649KNLmW/hyPQQvW022HejVuBifU3VIiJCcg3BEOU1RSOJdoynwuUmG81J4HBkRapLLqAOw28tWFx4nAAkAE16vk7xdpBbs4KoSDmGtZLO8lcaar2K8TKk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=YQ13ox0z; arc=none smtp.client-ip=209.85.128.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YQ13ox0z" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-43f106a3591so2535505e9.3; Sat, 10 May 2025 15:44:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917083; x=1747521883; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=B4h8GiUaOKYcTZ9vWZ/7AJmF0EHHcuCYihbQ0AxbIKc=; b=YQ13ox0zSdoW1SzX5OcrO831bRzEiKlpdDKlRaL4OTNd1sEZQ642p7kJ91VYdZiELR mPMe355kWpm3o070K0opys8LXDkRobCzVLYoDq9+duklfeGOfuAvneKrqIGDEeEztgZm OHQ4bqge6pbMUh9KPgHuMrsfmAxsy5LG+81/WzKjqCIaDHXxcYSxLjdA4U10+2LE6D+v EWgNq1ZpnjwanYZUnjvhFv4RWl15LEi7Fr6jfwwX8hvAJaR6gp5rTj0SvLOvW3GSXP2R xImotJx3OPCmZy8ryNhep4uwDdfetmxEF/GFtsvP3uC5/f1BR53oUUKDiC1Tr3GC2/pL BIxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917083; x=1747521883; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=B4h8GiUaOKYcTZ9vWZ/7AJmF0EHHcuCYihbQ0AxbIKc=; b=ubvCuxjSWCcm70D0NDQe+zV0pNwwmcN6a+uYP9FBT9fapzto6xgMIZzZKM9+nuZhAO icuoBVIOEm4Zu+aCuheCcHg8raPmYKuMUwG/ay4gFmvOaT/QW4c7se1JFMTH4shTZ54K z/S4TWftYBEWUIkVckFvh7SZDSGmx+S6q4MlzSiq9m5VElKecQh3pn+oki8OM4wnxD16 WisrN44s+F3ZLu0Ks4DWzxrn6yMdp9lMOpXftR+wCA2jrwjT7TzwrILsvdy49VLLZQ6p xo3M7WVyI8bG+7UyHEvtajJyP1oMyjySC/jdj/qxDKgM8ENlJfAPckQk9jLBjkfZ/SkT mo+w== X-Forwarded-Encrypted: i=1; AJvYcCWfUN/kBkpG5e1og9/lNWt72dMRr56Y5e7yRT4j/dvXTGuAPf7X6jHF+o00q+RNaPq2JlxlrR06NrxzDo8=@vger.kernel.org X-Gm-Message-State: AOJu0YzQdx+1H6DZdA8vz5kg4bhXX+2t5ALj4Kul5iBZsM2LvldOmzoZ rZOyeCzoTK4qKFfgFNWxo8gM12/GXMbZVD6CyFM+RORBf3MQTxBx X-Gm-Gg: ASbGncstx+NwTewcW3undRP+kLREa6Gg1gxUO+uMDEI50yIAyno2VBfVjJYAoCZlxy2 6IH6a41gWdVf0CHFlKg0Fqq02beOcFv5fyrepZaXNp8JTxx5GuWWI7paPbNcWu1pSOoewj6weBh qHkYpkO4uMLLstiGmyH97iXGbBjlbZUm1Ymi22dEvyretLLA9F56/saNW9Dz2nTAUFY2V7WG7aI eC8WNhYlgxPif5jVnpd1PU5QX4Gri7qY1T5vmInvOyix+wuYXym+w6tB2kYOz9P+QQa7aaKS9mN VwHTrtuf/Wktd+HjEku9LI8hqmk25ohpLMsC+fG1yjqLM1filgsbgNt3O6eNJGPsAcP30nQRXah O0JI+2AZW9I1x27VK3hUTuw== X-Google-Smtp-Source: AGHT+IEjHAyoBSW9B3IOrRnr35cA07ZWrvs0kjyIbxP1bTpt3GMGhgofdY0TSoKFGwt3WRS7+P9Gog== X-Received: by 2002:a5d:6489:0:b0:3a0:7d47:8d7e with SMTP id ffacd0b85a97d-3a1f643eb5dmr2019422f8f.8.1746917082882; Sat, 10 May 2025 15:44:42 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:42 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 4/7] iio: accel: adxl345: add inactivity feature Date: Sat, 10 May 2025 22:44:02 +0000 Message-Id: <20250510224405.17910-5-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the inactivity feature of the sensor. When activity and inactivity are enabled, a link bit will be set linking activity and inactivity handling. Additionally, the auto-sleep mode will be enabled. Due to the link bit the sensor is going to auto-sleep when inactivity was detected. Inactivity detection needs a threshold to be configured, and a time after which it will go into inactivity state if measurements under threshold. When a ODR is configured this time for inactivity is adjusted with a corresponding reasonable default value, in order to have higher frequencies and lower inactivity times, and lower sample frequency but give more time until inactivity. Both with reasonable upper and lower boundaries, since many of the sensor's features (e.g. auto-sleep) will need to operate beween 12.5 Hz and 400 Hz. This is a default setting when actively changing sample frequency, explicitly setting the time until inactivity will overwrite the default. Similarly, setting the g-range will provide a default value for the activity and inactivity thresholds. Both are implicit defaults, but equally can be overwritten to be explicitly configured. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 176 ++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 5 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index 32d014bd1e52..ba68f304035a 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -37,11 +37,17 @@ #define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) #define ADXL345_REG_TAP_SUPPRESS BIT(3) #define ADXL345_REG_ACT_AXIS_MSK GENMASK(6, 4) +#define ADXL345_REG_INACT_AXIS_MSK GENMASK(2, 0) +#define ADXL345_POWER_CTL_INACT_MSK (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL34= 5_POWER_CTL_LINK) =20 #define ADXL345_TAP_Z_EN BIT(0) #define ADXL345_TAP_Y_EN BIT(1) #define ADXL345_TAP_X_EN BIT(2) =20 +#define ADXL345_INACT_Z_EN BIT(0) +#define ADXL345_INACT_Y_EN BIT(1) +#define ADXL345_INACT_X_EN BIT(2) + #define ADXL345_ACT_Z_EN BIT(4) #define ADXL345_ACT_Y_EN BIT(5) #define ADXL345_ACT_X_EN BIT(6) @@ -72,14 +78,17 @@ static const unsigned int adxl345_tap_time_reg[] =3D { /* activity/inactivity */ enum adxl345_activity_type { ADXL345_ACTIVITY, + ADXL345_INACTIVITY, }; =20 static const unsigned int adxl345_act_int_reg[] =3D { [ADXL345_ACTIVITY] =3D ADXL345_INT_ACTIVITY, + [ADXL345_INACTIVITY] =3D ADXL345_INT_INACTIVITY, }; =20 static const unsigned int adxl345_act_thresh_reg[] =3D { [ADXL345_ACTIVITY] =3D ADXL345_REG_THRESH_ACT, + [ADXL345_INACTIVITY] =3D ADXL345_REG_THRESH_INACT, }; =20 enum adxl345_odr { @@ -214,10 +223,29 @@ enum adxl345_chans { chan_x, chan_y, chan_z, }; =20 +static const struct iio_event_spec adxl345_fake_chan_events[] =3D { + { + /* inactivity */ + .type =3D IIO_EV_TYPE_MAG, + .dir =3D IIO_EV_DIR_FALLING, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type =3D BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD), + }, +}; + static const struct iio_chan_spec adxl345_channels[] =3D { ADXL345_CHANNEL(0, chan_x, X), ADXL345_CHANNEL(1, chan_y, Y), ADXL345_CHANNEL(2, chan_z, Z), + { + .type =3D IIO_ACCEL, + .modified =3D 1, + .channel2 =3D IIO_MOD_X_AND_Y_AND_Z, + .scan_index =3D -1, /* Fake channel */ + .event_spec =3D adxl345_fake_chan_events, + .num_event_specs =3D ARRAY_SIZE(adxl345_fake_chan_events), + }, }; =20 static const unsigned long adxl345_scan_masks[] =3D { @@ -261,7 +289,8 @@ static int adxl345_set_measure_en(struct adxl345_state = *st, bool en) { unsigned int val =3D en ? ADXL345_POWER_CTL_MEASURE : ADXL345_POWER_CTL_S= TANDBY; =20 - return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val); + return regmap_update_bits(st->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_MEASURE, val); } =20 /* act/inact */ @@ -293,6 +322,21 @@ static int adxl345_is_act_inact_en(struct adxl345_stat= e *st, *en =3D false; return -EINVAL; } + } else { + switch (axis) { + case IIO_MOD_X: + *en =3D FIELD_GET(ADXL345_INACT_X_EN, axis_ctrl); + break; + case IIO_MOD_Y: + *en =3D FIELD_GET(ADXL345_INACT_Y_EN, axis_ctrl); + break; + case IIO_MOD_Z: + *en =3D FIELD_GET(ADXL345_INACT_Z_EN, axis_ctrl); + break; + default: + *en =3D false; + return -EINVAL; + } } =20 if (*en) { @@ -312,6 +356,7 @@ static int adxl345_set_act_inact_en(struct adxl345_stat= e *st, bool cmd_en) { bool en; + unsigned int inact_time_s; unsigned int threshold; u32 axis_ctrl =3D 0; int ret; @@ -330,6 +375,9 @@ static int adxl345_set_act_inact_en(struct adxl345_stat= e *st, default: return -EINVAL; } + } else { + axis_ctrl =3D ADXL345_INACT_X_EN | ADXL345_INACT_Y_EN | + ADXL345_INACT_Z_EN; } =20 if (cmd_en) @@ -350,11 +398,69 @@ static int adxl345_set_act_inact_en(struct adxl345_st= ate *st, if (type =3D=3D ADXL345_ACTIVITY) { en =3D FIELD_GET(ADXL345_REG_ACT_AXIS_MSK, axis_ctrl) && threshold; + } else { + ret =3D regmap_read(st->regmap, ADXL345_REG_TIME_INACT, &inact_time_s); + if (ret) + return ret; + + en =3D FIELD_GET(ADXL345_REG_INACT_AXIS_MSK, axis_ctrl) && + threshold && inact_time_s; } =20 - return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, - adxl345_act_int_reg[type], - en ? adxl345_act_int_reg[type] : 0); + ret =3D regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + adxl345_act_int_reg[type], + en ? adxl345_act_int_reg[type] : 0); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_INACT_MSK, + en ? (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL345_POWER_CTL_LINK) + : 0); +} + +/** + * adxl345_set_inact_time_s - Configure inactivity time explicitly or by O= DR. + * @st: The sensor state instance. + * @val_s: A desired time value, between 0 and 255. + * + * Inactivity time can be configured between 1 and 255 sec. If a val_s of 0 + * is configured by a user, then a default inactivity time will be compute= d. + * + * In such case, it should take power consumption into consideration. Thus= it + * shall be shorter for higher frequencies and longer for lower frequencie= s. + * Hence, frequencies above 255 Hz shall default to 10 s and frequencies b= elow + * 10 Hz shall result in 255 s to detect inactivity. + * + * The approach simply subtracts the pre-decimal figure of the configured + * sample frequency from 255 s to compute inactivity time [s]. Sub-Hz are = thus + * ignored in this estimation. The recommended ODRs for various features + * (activity/inactivity, sleep modes, free fall, etc.) lie between 12.5 Hz= and + * 400 Hz, thus higher or lower frequencies will result in the boundary + * defaults or need to be explicitly specified via val_s. + * + * Return: 0 or error value. + */ +static int adxl345_set_inact_time_s(struct adxl345_state *st, u32 val_s) +{ + unsigned int max_boundary =3D 255; + unsigned int min_boundary =3D 10; + unsigned int val =3D min(val_s, max_boundary); + enum adxl345_odr odr; + unsigned int regval; + int ret; + + if (val =3D=3D 0) { + ret =3D regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); + if (ret) + return ret; + odr =3D FIELD_GET(ADXL345_BW_RATE_MSK, regval); + + val =3D (adxl345_odr_tbl[odr][0] > max_boundary) + ? min_boundary : max_boundary - adxl345_odr_tbl[odr][0]; + } + + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); } =20 /* tap */ @@ -763,6 +869,13 @@ static int adxl345_read_event_config(struct iio_dev *i= ndio_dev, if (ret) return ret; return int_en; + case IIO_EV_DIR_FALLING: + ret =3D adxl345_is_act_inact_en(st, chan->channel2, + ADXL345_INACTIVITY, + &int_en); + if (ret) + return ret; + return int_en; default: return -EINVAL; } @@ -803,6 +916,10 @@ static int adxl345_write_event_config(struct iio_dev *= indio_dev, return adxl345_set_act_inact_en(st, chan->channel2, ADXL345_ACTIVITY, state); + case IIO_EV_DIR_FALLING: + return adxl345_set_act_inact_en(st, chan->channel2, + ADXL345_INACTIVITY, + state); default: return -EINVAL; } @@ -828,7 +945,8 @@ static int adxl345_read_event_value(struct iio_dev *ind= io_dev, int *val, int *val2) { struct adxl345_state *st =3D iio_priv(indio_dev); - unsigned int act_threshold; + unsigned int act_threshold, inact_threshold; + unsigned int inact_time_s; unsigned int tap_threshold; int ret; =20 @@ -846,9 +964,26 @@ static int adxl345_read_event_value(struct iio_dev *in= dio_dev, =20 *val =3D act_threshold; return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY], + &inact_threshold); + if (ret) + return ret; + + *val =3D inact_threshold; + return IIO_VAL_INT; default: return -EINVAL; } + case IIO_EV_INFO_PERIOD: + ret =3D regmap_read(st->regmap, + ADXL345_REG_TIME_INACT, + &inact_time_s); + if (ret) + return ret; + *val =3D inact_time_s; + return IIO_VAL_INT; default: return -EINVAL; } @@ -913,10 +1048,22 @@ static int adxl345_write_event_value(struct iio_dev = *indio_dev, if (ret) return ret; break; + case IIO_EV_DIR_FALLING: + ret =3D regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY], + val); + if (ret) + return ret; + break; default: return -EINVAL; } break; + case IIO_EV_INFO_PERIOD: + ret =3D adxl345_set_inact_time_s(st, val); + if (ret) + return ret; + break; default: return -EINVAL; } @@ -1201,6 +1348,17 @@ static int adxl345_push_event(struct iio_dev *indio_= dev, int int_stat, return ret; } =20 + if (FIELD_GET(ADXL345_INT_INACTIVITY, int_stat)) { + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + ts); + if (ret) + return ret; + } + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { samples =3D adxl345_get_samples(st); if (samples < 0) @@ -1432,10 +1590,18 @@ int adxl345_core_probe(struct device *dev, struct r= egmap *regmap, if (ret) return ret; =20 + ret =3D regmap_write(st->regmap, ADXL345_REG_TIME_INACT, 3); + if (ret) + return ret; + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6); if (ret) return ret; =20 + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_INACT, 4); + if (ret) + return ret; + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); if (ret) return ret; --=20 2.39.5 From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (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 08151220F24; Sat, 10 May 2025 22:44:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917089; cv=none; b=tWHjAgdljaBW8dnkhxiT0MiGY0xC8ghh0MJIo1cpAXZMJXO3YFvIMmHxQZ1d+H9ySQ36ozPxTPCb/n8QXGHjEvaXgvXXzfPRRTCThw+t1FBPJYuxapAzJMeqf7rYEcZZtMROOKtrS3rF7FE+eswxUjgYQ49tHAxi3cLX24lgo5o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917089; c=relaxed/simple; bh=804Ek70/ZGmvi349/t64PO/HGS2Wt9z08xXqQ/rSBD4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=IYWYIjhnfh0vBceIr/Zbq5jJke6s98D+yXmS7SKoXZGBVJQd6h6VCd1LCQ4Giodfr4hSUUUMawW0qiINddFA3u846YJTYQIsc2P2NCCYU+MozbzSkbgTeGNs3L8uJd6UdJn3LkY//nBvpBi+0qMiQx4bEl6QNF78r0mmVZPz4tw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=cC1EVwbC; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cC1EVwbC" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-3a0b77ea855so470544f8f.3; Sat, 10 May 2025 15:44:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917085; x=1747521885; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lABvRLlLyNPJg5J8U59g526kzNEubv4RkuPVEwpVoN8=; b=cC1EVwbC/vJRpiInm1QpP3G/dHBhKWG4D0syIbLUXoMzwM33K9WBIymSR35VYCZKtN 5oIGadwU4tzClPn0CAXo5vzkLEP3tF4NDUfgKPxwXfrNPb5RoMARBFx4aCuxAYhr18oW 7qHG1+6o9K3CT6NN3uYUkV0hguFXeGMEXQ+94lvuJ6EwuAnMBwAC/8VM60/woYzy4zob m1z/hPREn5uqyEPlbSn4SUWXGWG+iPXEFsRGbmhBtE4PvKhcF1OU030eGIVxtm0JiJh0 AhdVBinISrODCSkbBUNeYQD8weuIlxi3slpYrkhyQz13ls+U0elIoNE6WTU8wMWLXqr7 szLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917085; x=1747521885; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lABvRLlLyNPJg5J8U59g526kzNEubv4RkuPVEwpVoN8=; b=KGn3ffEkgWcqjTxpS0wjxsIrLQsyj1rTZQ3mmJnhjjrnyc6IlpGCTs3wpQDq745xEZ Mn1NOkJBAKAvlWcQj1y/cl8V710V1X4ClbBCwksWKm0FDqWUUACt5ITUVIx6IT241r5C uhYDOjsZnLv+6xHZSbprIIFnFquXtimqFpQXSHD1r+iPFUAk5sfCp978LXmdQSLmSyvx lqFmhUhwr0XIzwesfWDOcYv+rx7vTo5xVPbUjO07qAIpG8Kr/p3iLIw/2Hz+B0MM+Maw jitXJWlpc5Xrb7GarCxjvR+qGs3BziZPGVkKXHQ2WKLK+MvDfY6led+OVKOqfoJRii/D POnw== X-Forwarded-Encrypted: i=1; AJvYcCVOuSDgl0zARktBFxpMjEd6Owk/D5XA8EondM/FNi6yeajRpumqPGsLXzEXsx2quW5oRx3vxFr3vFe9wI0=@vger.kernel.org X-Gm-Message-State: AOJu0Yx808GSOL/3WQWttVpBc6/RMuz3vFtMJg7843jo82CbJS1HAeSu EMyfld7WLLl4TTiq7H4ipvRqq/Tnd1QrTa3OmAbMPMeWm3GFRAGw X-Gm-Gg: ASbGncsNeYryHrqrzn8sBR1klU3kexGFQWLNS1FoQXvlgFierob2RtUeAi0osEeBNLZ c4mJKlSpa9bAomdZYYpQFFo0YhbKSyIr9J5iycr+0s6vvEmFDl0aQjD+sAar3t1RFenm43P5ojE L/SSf0lv+Cq6fNT1blz7G2a3i0Cp7ZURHb1LzmF43KUIv70l0J/vxq9GsLiExCtEblC/MGO5jYp AkLPCzvAK2KX58dur6x66j+mZPGt85kYKMe59D6Rc1PAE9NuoxraSy1kWmbWbem/3M7EHCCmSiu 4RFewxOoUCV4T+AGQbbg3F4uazK/eQDVWdaL6gCyMe0bttNQIVbWAqDLe/3P+63AjqOxZ3y654d rnNir3ogyxPCAzPVOU1hxoQ== X-Google-Smtp-Source: AGHT+IE5WLd8Dn3t4A7/BKyLeGoMptgfZMxj/wKFGUWtLm7RwZIIkM9zJxSm1XAF/zMcmtNuIeBtzQ== X-Received: by 2002:a5d:59a8:0:b0:3a0:9dd1:bb59 with SMTP id ffacd0b85a97d-3a1f64a1f8dmr2425868f8f.15.1746917085205; Sat, 10 May 2025 15:44:45 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:44 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 5/7] iio: accel: adxl345: add coupling detection for activity/inactivity Date: Sat, 10 May 2025 22:44:03 +0000 Message-Id: <20250510224405.17910-6-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add coupling activity/inactivity detection by setting the AC/DC bit. This is an additional configuration to the activity and inactivity magnitude events, respectively. DC-coupled event generation takes the configured threshold values directly, where AC-coupled event generation references to the acceleration value at the start of the activity detection. New samples of acceleration are then compared to this reference. Both types are implemented using MAG for DC-coupled activity/inactivity, but MAG_REFERENCED for AC-coupled activity inactivity events. Threshold and periods are offerend by different sysfs handles, but share the same registers at the sensor. Thus activity and inactivity, respectively, cannot be configured with AC- and DC-coupling at the same time, e.g. configuring DC-coupled and AC-coupled activity will result in AC-coupled activity, or generally the most recent one being configured. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 362 +++++++++++++++++++++++++++++-- 1 file changed, 346 insertions(+), 16 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index ba68f304035a..c6f75d6b0db9 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -37,7 +37,9 @@ #define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) #define ADXL345_REG_TAP_SUPPRESS BIT(3) #define ADXL345_REG_ACT_AXIS_MSK GENMASK(6, 4) +#define ADXL345_REG_ACT_ACDC_MSK BIT(7) #define ADXL345_REG_INACT_AXIS_MSK GENMASK(2, 0) +#define ADXL345_REG_INACT_ACDC_MSK BIT(3) #define ADXL345_POWER_CTL_INACT_MSK (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL34= 5_POWER_CTL_LINK) =20 #define ADXL345_TAP_Z_EN BIT(0) @@ -52,6 +54,9 @@ #define ADXL345_ACT_Y_EN BIT(5) #define ADXL345_ACT_X_EN BIT(6) =20 +#define ADXL345_ACT_INACT_DC 0 +#define ADXL345_ACT_INACT_AC 1 + /* single/double tap */ enum adxl345_tap_type { ADXL345_SINGLE_TAP, @@ -79,16 +84,29 @@ static const unsigned int adxl345_tap_time_reg[] =3D { enum adxl345_activity_type { ADXL345_ACTIVITY, ADXL345_INACTIVITY, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, }; =20 static const unsigned int adxl345_act_int_reg[] =3D { [ADXL345_ACTIVITY] =3D ADXL345_INT_ACTIVITY, [ADXL345_INACTIVITY] =3D ADXL345_INT_INACTIVITY, + [ADXL345_ACTIVITY_AC] =3D ADXL345_INT_ACTIVITY, + [ADXL345_INACTIVITY_AC] =3D ADXL345_INT_INACTIVITY, }; =20 static const unsigned int adxl345_act_thresh_reg[] =3D { [ADXL345_ACTIVITY] =3D ADXL345_REG_THRESH_ACT, [ADXL345_INACTIVITY] =3D ADXL345_REG_THRESH_INACT, + [ADXL345_ACTIVITY_AC] =3D ADXL345_REG_THRESH_ACT, + [ADXL345_INACTIVITY_AC] =3D ADXL345_REG_THRESH_INACT, +}; + +static const unsigned int adxl345_act_acdc_msk[] =3D { + [ADXL345_ACTIVITY] =3D ADXL345_REG_ACT_ACDC_MSK, + [ADXL345_INACTIVITY] =3D ADXL345_REG_INACT_ACDC_MSK, + [ADXL345_ACTIVITY_AC] =3D ADXL345_REG_ACT_ACDC_MSK, + [ADXL345_INACTIVITY_AC] =3D ADXL345_REG_INACT_ACDC_MSK, }; =20 enum adxl345_odr { @@ -156,6 +174,14 @@ static const int adxl345_fullres_range_tbl[][2] =3D { [ADXL345_16G_RANGE] =3D { 0, 38312 }, }; =20 +/* scaling */ +static const int adxl345_range_factor_tbl[] =3D { + [ADXL345_2G_RANGE] =3D 1, + [ADXL345_4G_RANGE] =3D 2, + [ADXL345_8G_RANGE] =3D 4, + [ADXL345_16G_RANGE] =3D 8, +}; + struct adxl345_state { const struct adxl345_chip_info *info; struct regmap *regmap; @@ -179,6 +205,13 @@ static struct iio_event_spec adxl345_events[] =3D { .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), .mask_shared_by_type =3D BIT(IIO_EV_INFO_VALUE), }, + { + /* activity, ac bit set */ + .type =3D IIO_EV_TYPE_MAG_REFERENCED, + .dir =3D IIO_EV_DIR_RISING, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type =3D BIT(IIO_EV_INFO_VALUE), + }, { /* single tap */ .type =3D IIO_EV_TYPE_GESTURE, @@ -232,6 +265,14 @@ static const struct iio_event_spec adxl345_fake_chan_e= vents[] =3D { .mask_shared_by_type =3D BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_PERIOD), }, + { + /* inactivity, AC bit set */ + .type =3D IIO_EV_TYPE_MAG_REFERENCED, + .dir =3D IIO_EV_DIR_FALLING, + .mask_separate =3D BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type =3D BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD), + }, }; =20 static const struct iio_chan_spec adxl345_channels[] =3D { @@ -295,19 +336,119 @@ static int adxl345_set_measure_en(struct adxl345_sta= te *st, bool en) =20 /* act/inact */ =20 +/** + * adxl345_is_act_inact_ac() - Verify if AC or DC coupling is currently en= abled. + * + * @st: The device data. + * @type: The activity or inactivity type. + * @en: Carries the result if this activity type is enabled. + * + * Given a type of activity / inactivity combined with either AC coupling = set or + * default to DC, this function verifies if the combination is currently + * configured, hence enabled or not. + * + * Return: 0 if successful, else error value. + */ +static int adxl345_is_act_inact_ac(struct adxl345_state *st, + enum adxl345_activity_type type, bool *en) +{ + unsigned int regval; + bool ac; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + if (type =3D=3D ADXL345_ACTIVITY || type =3D=3D ADXL345_ACTIVITY_AC) + ac =3D FIELD_GET(ADXL345_REG_ACT_ACDC_MSK, regval); + else + ac =3D FIELD_GET(ADXL345_REG_INACT_ACDC_MSK, regval); + + if (type =3D=3D ADXL345_ACTIVITY || type =3D=3D ADXL345_INACTIVITY) + *en =3D (ac =3D=3D ADXL345_ACT_INACT_DC); + else + *en =3D (ac =3D=3D ADXL345_ACT_INACT_AC); + + return 0; +} + +/** + * adxl345_set_act_inact_ac() - Configure AC coupling or DC coupling. + * + * @st: The device data. + * @type: Provide a type of activity or inactivity. + * + * Enables AC coupling or DC coupling depending on the provided type argum= ent. + * Note: Activity and inactivity can be either AC coupled or DC coupled not + * both at the same time. + * + * Return: 0 if successful, else error value. + */ +static int adxl345_set_act_inact_ac(struct adxl345_state *st, + enum adxl345_activity_type type) +{ + unsigned int act_inact_ac; + + if (type =3D=3D ADXL345_ACTIVITY_AC || type =3D=3D ADXL345_INACTIVITY_AC) + act_inact_ac =3D 0xff; + else + act_inact_ac =3D 0x00; + + /* + * A setting of false selects dc-coupled operation, and a setting of + * true enables ac-coupled operation. In dc-coupled operation, the + * current acceleration magnitude is compared directly with + * ADXL345_REG_THRESH_ACT and ADXL345_REG_THRESH_INACT to determine + * whether activity or inactivity is detected. + * + * In ac-coupled operation for activity detection, the acceleration + * value at the start of activity detection is taken as a reference + * value. New samples of acceleration are then compared to this + * reference value, and if the magnitude of the difference exceeds the + * ADXL345_REG_THRESH_ACT value, the device triggers an activity + * interrupt. + * + * Similarly, in ac-coupled operation for inactivity detection, a + * reference value is used for comparison and is updated whenever the + * device exceeds the inactivity threshold. After the reference value + * is selected, the device compares the magnitude of the difference + * between the reference value and the current acceleration with + * ADXL345_REG_THRESH_INACT. If the difference is less than the value in + * ADXL345_REG_THRESH_INACT for the time in ADXL345_REG_TIME_INACT, the + * device is considered inactive and the inactivity interrupt is + * triggered. [quoted from p. 24, ADXL345 datasheet Rev. G] + * + * In a conclusion, the first acceleration snapshot sample which hit the + * threshold in a particular direction is always taken as acceleration + * reference value to that direction. Since for the hardware activity + * and inactivity depend on the x/y/z axis, so do ac and dc coupling. + * Note, this sw driver always enables or disables all three x/y/z axis + * for detection via act_axis_ctrl and inact_axis_ctrl, respectively. + * Where in dc-coupling samples are compared against the thresholds, in + * ac-coupling measurement difference to the first acceleration + * reference value are compared against the threshold. So, ac-coupling + * allows for a bit more dynamic compensation depending on the initial + * sample. + */ + return regmap_update_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL, + adxl345_act_acdc_msk[type], act_inact_ac); +} + static int adxl345_is_act_inact_en(struct adxl345_state *st, enum iio_modifier axis, enum adxl345_activity_type type, bool *en) { unsigned int regval; u32 axis_ctrl; + bool coupling_en; int ret; =20 ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl); if (ret) return ret; =20 - if (type =3D=3D ADXL345_ACTIVITY) { + if (type =3D=3D ADXL345_ACTIVITY || type =3D=3D ADXL345_ACTIVITY_AC) { switch (axis) { case IIO_MOD_X: *en =3D FIELD_GET(ADXL345_ACT_X_EN, axis_ctrl); @@ -345,6 +486,12 @@ static int adxl345_is_act_inact_en(struct adxl345_stat= e *st, return ret; =20 *en =3D adxl345_act_int_reg[type] & regval; + + ret =3D adxl345_is_act_inact_ac(st, type, &coupling_en); + if (ret) + return ret; + + *en =3D adxl345_act_int_reg[type] && coupling_en; } =20 return 0; @@ -361,7 +508,7 @@ static int adxl345_set_act_inact_en(struct adxl345_stat= e *st, u32 axis_ctrl =3D 0; int ret; =20 - if (type =3D=3D ADXL345_ACTIVITY) { + if (type =3D=3D ADXL345_ACTIVITY || type =3D=3D ADXL345_ACTIVITY_AC) { switch (axis) { case IIO_MOD_X: axis_ctrl =3D ADXL345_ACT_X_EN; @@ -395,7 +542,7 @@ static int adxl345_set_act_inact_en(struct adxl345_stat= e *st, =20 en =3D false; =20 - if (type =3D=3D ADXL345_ACTIVITY) { + if (type =3D=3D ADXL345_ACTIVITY || type =3D=3D ADXL345_ACTIVITY_AC) { en =3D FIELD_GET(ADXL345_REG_ACT_AXIS_MSK, axis_ctrl) && threshold; } else { @@ -413,6 +560,10 @@ static int adxl345_set_act_inact_en(struct adxl345_sta= te *st, if (ret) return ret; =20 + ret =3D adxl345_set_act_inact_ac(st, type); + if (ret) + return ret; + return regmap_update_bits(st->regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_INACT_MSK, en ? (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL345_POWER_CTL_LINK) @@ -692,9 +843,16 @@ static int adxl345_find_odr(struct adxl345_state *st, = int val, =20 static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr) { - return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, + int ret; + + ret =3D regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, ADXL345_BW_RATE_MSK, FIELD_PREP(ADXL345_BW_RATE_MSK, odr)); + if (ret) + return ret; + + /* update inactivity time by ODR */ + return adxl345_set_inact_time_s(st, 0); } =20 static int adxl345_find_range(struct adxl345_state *st, int val, int val2, @@ -715,9 +873,51 @@ static int adxl345_find_range(struct adxl345_state *st= , int val, int val2, =20 static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range = range) { - return regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, + unsigned int act_threshold, inact_threshold; + unsigned int range_old; + unsigned int regval; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, ®val); + if (ret) + return ret; + range_old =3D FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval); + + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_ACTIVITY], + &act_threshold); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY], + &inact_threshold); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, ADXL345_DATA_FORMAT_RANGE, FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range)); + if (ret) + return ret; + + act_threshold =3D act_threshold + * adxl345_range_factor_tbl[range_old] + / adxl345_range_factor_tbl[range]; + act_threshold =3D min(255, max(1, inact_threshold)); + + inact_threshold =3D inact_threshold + * adxl345_range_factor_tbl[range_old] + / adxl345_range_factor_tbl[range]; + inact_threshold =3D min(255, max(1, inact_threshold)); + + ret =3D regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_ACTIVITY], + act_threshold); + if (ret) + return ret; + + return regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_INACTIVITY= ], + inact_threshold); } =20 static int adxl345_read_avail(struct iio_dev *indio_dev, @@ -879,6 +1079,25 @@ static int adxl345_read_event_config(struct iio_dev *= indio_dev, default: return -EINVAL; } + case IIO_EV_TYPE_MAG_REFERENCED: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D adxl345_is_act_inact_en(st, chan->channel2, + ADXL345_ACTIVITY_AC, + &int_en); + if (ret) + return ret; + return int_en; + case IIO_EV_DIR_FALLING: + ret =3D adxl345_is_act_inact_en(st, chan->channel2, + ADXL345_INACTIVITY_AC, + &int_en); + if (ret) + return ret; + return int_en; + default: + return -EINVAL; + } case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -923,6 +1142,19 @@ static int adxl345_write_event_config(struct iio_dev = *indio_dev, default: return -EINVAL; } + case IIO_EV_TYPE_MAG_REFERENCED: + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl345_set_act_inact_en(st, chan->channel2, + ADXL345_ACTIVITY_AC, + state); + case IIO_EV_DIR_FALLING: + return adxl345_set_act_inact_en(st, chan->channel2, + ADXL345_INACTIVITY_AC, + state); + default: + return -EINVAL; + } case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -987,6 +1219,42 @@ static int adxl345_read_event_value(struct iio_dev *i= ndio_dev, default: return -EINVAL; } + case IIO_EV_TYPE_MAG_REFERENCED: + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_ACTIVITY_AC], + &act_threshold); + if (ret) + return ret; + + *val =3D act_threshold; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY_AC], + &inact_threshold); + if (ret) + return ret; + + *val =3D inact_threshold; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_EV_INFO_PERIOD: + ret =3D regmap_read(st->regmap, + ADXL345_REG_TIME_INACT, + &inact_time_s); + if (ret) + return ret; + *val =3D inact_time_s; + return IIO_VAL_INT; + default: + return -EINVAL; + } case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -1068,6 +1336,37 @@ static int adxl345_write_event_value(struct iio_dev = *indio_dev, return -EINVAL; } break; + case IIO_EV_TYPE_MAG_REFERENCED: + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_ACTIVITY_AC], + val); + if (ret) + return ret; + break; + case IIO_EV_DIR_FALLING: + ret =3D regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY_AC], + val); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + break; + case IIO_EV_INFO_PERIOD: + ret =3D adxl345_set_inact_time_s(st, val); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + break; case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -1315,6 +1614,7 @@ static int adxl345_push_event(struct iio_dev *indio_d= ev, int int_stat, { s64 ts =3D iio_get_time_ns(indio_dev); struct adxl345_state *st =3D iio_priv(indio_dev); + unsigned int regval; int samples; int ret =3D -ENOENT; =20 @@ -1339,22 +1639,52 @@ static int adxl345_push_event(struct iio_dev *indio= _dev, int int_stat, } =20 if (FIELD_GET(ADXL345_INT_ACTIVITY, int_stat)) { - ret =3D iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - ts); + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + if (FIELD_GET(ADXL345_REG_ACT_ACDC_MSK, regval)) { + /* AC coupled */ + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, + IIO_EV_TYPE_MAG_REFERENCED, + IIO_EV_DIR_RISING), + ts); + + } else { + /* DC coupled, relying on THRESH */ + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + ts); + } if (ret) return ret; } =20 if (FIELD_GET(ADXL345_INT_INACTIVITY, int_stat)) { - ret =3D iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, - IIO_MOD_X_AND_Y_AND_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_FALLING), - ts); + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + if (FIELD_GET(ADXL345_REG_INACT_ACDC_MSK, regval)) { + /* AC coupled */ + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG_REFERENCED, + IIO_EV_DIR_FALLING), + ts); + } else { + /* DC coupled, relying on THRESH */ + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + ts); + } if (ret) return ret; } --=20 2.39.5 From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.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 CEC1E213E8E; Sat, 10 May 2025 22:44:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917090; cv=none; b=C5+uGwW0RlYH6sLDltIOyx35uZkALy5oHPSkp1qZhLJ75H7zjoUj1hpCZ9g0Bh1BSaXYTNRgMhw3dT4c8SmIpYUahLuR4eQYU7tOaAOKcdzqNiV0LXPGuPvyR2ArobxWrjadhnkW+OTNAVNyjHOLxnz9/WUcOlPhpc5G7JLC4PM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917090; c=relaxed/simple; bh=4cCrXv7PqnLYXsDYHVGS4wgMfsUAbmAFmbPpeLAblRg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DY1dokuITTj8S8j3us3f+w0CfyAQX9THR7DpThVEMbbEI1zo3fb03ZN8YfGbti3mmjOoT8A6I/mXYkR+C7Ab0yDQwH/zE1Xp/hPTXItEEi/F526oUrn7fwKSmEoebHeGRAMIXcY0NGKwVTfN54vRibGL3mMdEIVCg82yxIvUsCc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CbGBJNeb; arc=none smtp.client-ip=209.85.221.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CbGBJNeb" Received: by mail-wr1-f51.google.com with SMTP id ffacd0b85a97d-3a0b201faedso317717f8f.0; Sat, 10 May 2025 15:44:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917087; x=1747521887; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Lqzm7oJMiOVQKzBfgE1ECHlMCNzrhjvmVtbI/5TygPE=; b=CbGBJNeb2ujoo2BDqS0xwe2ONWqnEn4onS/+SbCloAjy36BlyCxRR2jbteF2vLVofD JRT7CWPdepXncvbW7ybtMr/kuRTnRvWOqk7rARNs7TSaXJuHGEn0AU84hq2TnM4v7v/Y Fc40EOJjd/umy4kIlITjtgvloStjPHwTpE6rM2l46hl6JPBbjctaDAsZrOuSjQ53XuSQ X/HjWT1YGDjPdNA155lb4NsyGAtERjxnv9y2NzdmEFQVoVGu0Fw2aYN888wdY9dNJeEK rwpOUfwtyaPcMI3gghRlg6+dQfKyu3FnWqHTeWAXKSQzxaFY1hdNj5sLPjm6+udyTCtv jgmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917087; x=1747521887; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Lqzm7oJMiOVQKzBfgE1ECHlMCNzrhjvmVtbI/5TygPE=; b=Bx38xS/EyhJBW7qMFaCsWJYQ8nW9OFRMcMlDopzCv5Fp9wQP3S4hAQAsOlHA1YObH+ EIib/mB4fw5KhwCzPaQRYlkMmXdmnDwaVitDHQYj597OnsXA9bZt8DW2F60GXBdFXwQA ST260AAA3hCic8VG5lk0d1clC2ggtQv+ee2s7gOI2VVQLXx+LrGvW5RtWDVOyxAdZL/n fOgqFaAWmb1uzMRyxqCplYfoW/zYUnqPL1/qLwizd22OGifjRSt79CKFX+/1y88JIVm5 gtgD+bh3ipJKDzV/Pyes2OIgozCu0jnVJpOnHd1H7F0gRP/HWm7JU9E59lC0oTPStqOB nLXA== X-Forwarded-Encrypted: i=1; AJvYcCVgrnSQ27TTR1alJ2feU37HJCLRn4HzcXrHvedQb6h/MKKa67Ut4JZQhGBMI8YXnmrEMvWiY2kxlaXb3c4=@vger.kernel.org X-Gm-Message-State: AOJu0YwR4d9uDcGl26+Aq+0GzuEFqqUc3G981YNXKbtpxH8cgdv5JpBw joE49an3Gurpcp92vnEYNSzqKzFDFDbCkg2m6NMD2zeusgZqEFYpON9jVg/f X-Gm-Gg: ASbGnctFKp1n62mDHuufktea6ZumDhDZYOiOQRsajpgDMXyFayuM5yEYB+zkn9lVp1+ H+NTkFkvty4FuYThnPTvsAqjmrq+UE0yjX2nqkWwKhhx9ksXj3wpMpUZrCbpPn9GU/KvjgR9e3W Hu2LIvDXY0AsRh+QaxzGbzWE/LvFt+XWBu6IemoxFGLlDar6tkIib527zWhEN8+O1N2moLMhGz6 F4sVtQQ93q/bR1u4p8OwCPy/mLzuaXkSfhTbx8GNr1e8MMqdd5OFkZSHw0kdkd3za53dKacj020 LtwYyV35/QB/u5rHZok7hgRskVXRUWkP0YdDdYvzDXYQ1XznDdd18LqRgb3WBf5LtpAtD6tYpnE TIDD8EtTNO05oujNrH7Ag9Q== X-Google-Smtp-Source: AGHT+IGOoGKVI9My26N4X2o7qC0/7+Tn1hXKo7wzVGhHRzdNRMkwTzgd2WCEhkLC/4nVJSemV/lVvw== X-Received: by 2002:a05:6000:2011:b0:39c:1efb:ee87 with SMTP id ffacd0b85a97d-3a1f648123fmr2195792f8f.12.1746917086865; Sat, 10 May 2025 15:44:46 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:45 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 6/7] iio: accel: adxl345: add freefall feature Date: Sat, 10 May 2025 22:44:04 +0000 Message-Id: <20250510224405.17910-7-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the freefall detection of the sensor together with a threshold and time parameter. A freefall magnitude event is detected if the measuring signal falls below the threshold. Introduce a freefall threshold stored in regmap cache, and a freefall time, having the scaled time value stored as a member variable in the state instance. The generated IIO event is a magnitude event on x&y&z and thus identical to what inactivity (with DC-coupling default) would generate. Thus a separate set of sysfs handles are setup to configure and enable freefall events. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 226 +++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index c6f75d6b0db9..c35a5727852c 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -193,6 +193,7 @@ struct adxl345_state { u32 tap_duration_us; u32 tap_latent_us; u32 tap_window_us; + u32 ff_time_ms; =20 __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_M= INALIGN); }; @@ -825,6 +826,63 @@ static int adxl345_set_tap_latent(struct adxl345_state= *st, u32 val_int, return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us); } =20 +/* free-fall */ + +static int adxl345_is_ff_en(struct adxl345_state *st, bool *en) +{ + int ret; + unsigned int regval; + + ret =3D regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val); + if (ret) + return ret; + + *en =3D FIELD_GET(ADXL345_INT_FREE_FALL, regval) > 0; + + return 0; +} + +static int adxl345_set_ff_en(struct adxl345_state *st, bool cmd_en) +{ + unsigned int regval, ff_threshold; + bool en; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_THRESH_FF, &ff_threshold); + if (ret) + return ret; + + en =3D cmd_en && ff_threshold > 0 && st->ff_time_ms > 0; + + regval =3D en ? ADXL345_INT_FREE_FALL : 0x00; + + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + ADXL345_INT_FREE_FALL, regval); +} + +static int adxl345_set_ff_time(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + unsigned int regval; + int val_ms; + + /* + * max value is 255 * 5000 us =3D 1.275000 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (1000000 * val_int + val_fract_us > 1275000) + return -EINVAL; + + val_ms =3D val_int * 1000 + DIV_ROUND_UP(val_fract_us, 1000); + st->ff_time_ms =3D val_ms; + + regval =3D DIV_ROUND_CLOSEST(val_ms, 5); + + /* Values between 100ms and 350ms (0x14 to 0x46) are recommended. */ + return regmap_write(st->regmap, ADXL345_REG_TIME_FF, min(regval, 0xff)); +} + static int adxl345_find_odr(struct adxl345_state *st, int val, int val2, enum adxl345_odr *odr) { @@ -1689,6 +1747,17 @@ static int adxl345_push_event(struct iio_dev *indio_= dev, int int_stat, return ret; } =20 + if (FIELD_GET(ADXL345_INT_FREE_FALL, int_stat)) { + ret =3D iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + ts); + if (ret) + return ret; + } + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { samples =3D adxl345_get_samples(st); if (samples < 0) @@ -1763,7 +1832,156 @@ static irqreturn_t adxl345_irq_handler(int irq, voi= d *p) return IRQ_HANDLED; } =20 +/* free-fall sysfs */ + +static ssize_t in_accel_mag_freefall_en_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct adxl345_state *st =3D iio_priv(indio_dev); + bool en; + int val, ret; + + ret =3D adxl345_is_ff_en(st, &en); + if (ret) + return ret; + + val =3D en ? 1 : 0; + + return iio_format_value(buf, IIO_VAL_INT, 1, &val); +} + +static ssize_t in_accel_mag_freefall_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct adxl345_state *st =3D iio_priv(indio_dev); + int val, ret; + + ret =3D kstrtoint(buf, 0, &val); + if (ret) + return ret; + + ret =3D adxl345_set_measure_en(st, false); + if (ret) + return ret; + + ret =3D adxl345_set_ff_en(st, val > 0); + if (ret) + return ret; + + ret =3D adxl345_set_measure_en(st, true); + if (ret) + return ret; + + return len; +} +static IIO_DEVICE_ATTR_RW(in_accel_mag_freefall_en, 0); + +static ssize_t in_accel_mag_freefall_value_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct adxl345_state *st =3D iio_priv(indio_dev); + unsigned int val; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_THRESH_FF, &val); + if (ret) + return ret; + + return iio_format_value(buf, IIO_VAL_INT, 1, &val); +} + +static ssize_t in_accel_mag_freefall_value_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct adxl345_state *st =3D iio_priv(indio_dev); + int val, ret; + + ret =3D kstrtoint(buf, 0, &val); + if (ret) + return ret; + + if (val < 0 || val > 255) + return -EINVAL; + + ret =3D adxl345_set_measure_en(st, false); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_FF, val); + if (ret) + return ret; + + ret =3D adxl345_set_measure_en(st, true); + if (ret) + return ret; + + return len; +} +static IIO_DEVICE_ATTR_RW(in_accel_mag_freefall_value, 0); + +static ssize_t in_accel_mag_freefall_period_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct adxl345_state *st =3D iio_priv(indio_dev); + int vals[2]; + + vals[0] =3D st->ff_time_ms; + vals[1] =3D 1000; + + return iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, vals); +} + +static ssize_t in_accel_mag_freefall_period_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct adxl345_state *st =3D iio_priv(indio_dev); + int val_int, val_fract_us, ret; + + ret =3D iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract_us); + if (ret) + return ret; + + ret =3D adxl345_set_measure_en(st, false); + if (ret) + return ret; + + ret =3D adxl345_set_ff_time(st, val_int, val_fract_us); + if (ret) + return ret; + + ret =3D adxl345_set_measure_en(st, true); + if (ret) + return ret; + + return len; +} +static IIO_DEVICE_ATTR_RW(in_accel_mag_freefall_period, 0); + +static struct attribute *adxl345_event_attrs[] =3D { + &iio_dev_attr_in_accel_mag_freefall_en.dev_attr.attr, + &iio_dev_attr_in_accel_mag_freefall_value.dev_attr.attr, + &iio_dev_attr_in_accel_mag_freefall_period.dev_attr.attr, + NULL +}; + +static const struct attribute_group adxl345_event_attrs_group =3D { + .attrs =3D adxl345_event_attrs, +}; + static const struct iio_info adxl345_info =3D { + .event_attrs =3D &adxl345_event_attrs_group, .read_raw =3D adxl345_read_raw, .write_raw =3D adxl345_write_raw, .read_avail =3D adxl345_read_avail, @@ -1806,6 +2024,7 @@ int adxl345_core_probe(struct device *dev, struct reg= map *regmap, ADXL345_DATA_FORMAT_FULL_RES | ADXL345_DATA_FORMAT_SELF_TEST); unsigned int tap_threshold; + unsigned int ff_threshold; int ret; =20 indio_dev =3D devm_iio_device_alloc(dev, sizeof(*st)); @@ -1825,6 +2044,9 @@ int adxl345_core_probe(struct device *dev, struct reg= map *regmap, st->tap_window_us =3D 64; /* 64 [0x40] -> .080 */ st->tap_latent_us =3D 16; /* 16 [0x10] -> .020 */ =20 + ff_threshold =3D 8; /* 8 [0x08] */ + st->ff_time_ms =3D 32; /* 32 [0x20] -> 0.16 */ + indio_dev->name =3D st->info->name; indio_dev->info =3D &adxl345_info; indio_dev->modes =3D INDIO_DIRECT_MODE; @@ -1936,6 +2158,10 @@ int adxl345_core_probe(struct device *dev, struct re= gmap *regmap, if (ret) return ret; =20 + ret =3D regmap_write(st->regmap, ADXL345_REG_THRESH_FF, ff_threshold); + if (ret) + return ret; + /* FIFO_STREAM mode is going to be activated later */ ret =3D devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops); if (ret) --=20 2.39.5 From nobody Sat Feb 7 12:29:45 2026 Received: from mail-wr1-f53.google.com (mail-wr1-f53.google.com [209.85.221.53]) (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 40C77223DD4; Sat, 10 May 2025 22:44:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917094; cv=none; b=nMfOSSrHuGv7L27EPAnHhyADshX0cGbw1mtutl2yB7kDas6VAP22OI5kQQefF7gv9xGrACQOIdnJY+HxL7kR2LdSJSU7UR25MK1beYp8co/o3N0OVGbo1rus+WAsWL6/qslcrnwHZ2pdNLFTf0fFhUeeRjcD9XGvzs8VF+IaaD0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746917094; c=relaxed/simple; bh=4Xz5KZDz24ti8L/apPYOP7xXeFRY6Hd7wsMainWv4D4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=kVDGSBKuE5HE0wKv3Pd+U1RReRwEYZySSd4gymtA0z9fhgzgm8wuoqPFuz2/wIvT2ISlT+23+Y8a/WLJvoKPnsC/ciIMfoPPq3kLdN8yr4rjcbAqnFqZJQkg8KB+7zADzlMbf27vdLuIc+AVoNXnqNHqhFyAAz/8i0IqvcZZ/iQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=iMrSOgBk; arc=none smtp.client-ip=209.85.221.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iMrSOgBk" Received: by mail-wr1-f53.google.com with SMTP id ffacd0b85a97d-39d73b97500so208336f8f.3; Sat, 10 May 2025 15:44:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746917089; x=1747521889; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Gn3R+rOQ1OKbd846716wKmytorBAFqdUEALN8Wt6YpU=; b=iMrSOgBkSPJ615lehA59En2ZMsutTznIbTu3Z1U62JyeXH2uw+KhE7EDJgVTMoLHXL 41Yyw5zUOa61pbyVZQph46RwZSCM8LHBCtoocQmZ5OlKopg4jEZvbhSv39ycv8fe5x9A CPiMcO8NVw/D+CMvi5PvE3+/wDIP7mHv30gNx4irL1l2V4JBLQmPrPFH5MozL2zQX/Yt 5AKcaWYE/7zK16tgbxsWKm66wKmK91E+6xIGdEt8wNRNhiF0Ex54Ne4vckXh+F8Di+/X GM34HNk+B4rDMSpN70bpNVUuQw7lTHsphnXmFPDf4qvkalrgzAdByzfsbiSjgTOs+p2F 9Vpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746917089; x=1747521889; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Gn3R+rOQ1OKbd846716wKmytorBAFqdUEALN8Wt6YpU=; b=hgf/a2VsQKNXSo+CHY4O2tkOtYkNb/KbOeJhB89ZOxvbdWS/qLWZyCHPIeEg0mnTRi wICNgAg7j3wJ6SorzK34F1rMcAZRduKX2MixH6VmyFmyKO9ud1zI4FdPyaUxhbFfZ9/y SxCEng45Zv9xJuEwZkhKnjIIP8Z3eOnkeNA+85wy6y9WdVNfeRNe0r0GYHD6kSfwPUUH vmtZLuxTC4pUJM9Li6Pu4iglXhi3gyQNktHqv8U7x4tmQ8hs8KBXMNuwxrGNALzmB+gb 4CNxHzSXOBLrE0F2//S3OXHzR9o+RPZhTvxY+ML91P/DB9q4fB/M/lfftqIkqoh/Y5uf 3mwg== X-Forwarded-Encrypted: i=1; AJvYcCXqPOOSFVj56G822uQvMSd30y9DIfkbV3KVsUGq0aBF+31VG5BnSttYH4Co8Y7VXHy8OGQaViJnhQuhpYg=@vger.kernel.org X-Gm-Message-State: AOJu0Yz8X21wB92B17kqFM5nEuEbSlM5txRTqHtxm0uFjjrrW/6rXgIu ywWsJFIrSHzo/trBzhsZPTWkpxMoIoEitt3+Y9DlLzy1AFGHYLPI X-Gm-Gg: ASbGncv26bbPPhYFlmPONFNV9OvWjUIy7DOtHzOrYEKYTizapulENRSngjzQjnSMtKu pFPSyliKqo0R2nJuQfgCnx0Zwp9GmrzuSfQlPeIioWzHmTDwkhiBaKHb+sDB4XIkRAvQejHqE3H Dr8BXwWWbyYbw2vP+2Q8Z3undnJB+tZZMQiW2UhOaujk5oZDe5J10kMLvK5ezUZysArOzajs5Pj xPLVJVDrCBUYrE/0qASQQ9XuOj2gfLocYhgm/jtx2R+87msD9KkhEEpcV2hYk4dmckeE7P8mUH0 Tbxt80tHKDhZ4+AN8JboVRpGgmv2oR1cONKdG7oNFY870DeplZhJcy3tg4ariIa4ptzNeXuTnrk uN93os+Tvo2t2FDoka40YlYMKsGadkFCg X-Google-Smtp-Source: AGHT+IF/kevzwUSv2fDMlUCfRGH7kqv2lXwdbx4pOJdPCQcSYmW7N/G1vs5Mfl3Z+UM8eRKwvvtpxg== X-Received: by 2002:a05:6000:2ce:b0:3a0:b6c3:9b80 with SMTP id ffacd0b85a97d-3a1f64401b1mr2470222f8f.6.1746917089235; Sat, 10 May 2025 15:44:49 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a1f58f2f65sm7701015f8f.55.2025.05.10.15.44.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 May 2025 15:44:48 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v8 7/7] docs: iio: add documentation for adxl345 driver Date: Sat, 10 May 2025 22:44:05 +0000 Message-Id: <20250510224405.17910-8-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250510224405.17910-1-l.rubusch@gmail.com> References: <20250510224405.17910-1-l.rubusch@gmail.com> 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 The documentation describes the ADXL345 driver, IIO interface, interface usage and configuration. Signed-off-by: Lothar Rubusch --- Documentation/iio/adxl345.rst | 458 ++++++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+) create mode 100644 Documentation/iio/adxl345.rst diff --git a/Documentation/iio/adxl345.rst b/Documentation/iio/adxl345.rst new file mode 100644 index 000000000000..e21b783153a6 --- /dev/null +++ b/Documentation/iio/adxl345.rst @@ -0,0 +1,458 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +ADXL345 driver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver supports Analog Device's ADXL345/375 on SPI/I2C bus. + +1. Supported Devices +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +* `ADXL345 `_ +* `ADXL375 `_ + +The ADXL345 is a generic purpose low power, 3-axis accelerometer with sele= ctable +measurement ranges. The ADXL345 supports the =C2=B12 g, =C2=B14 g, =C2=B18= g, and =C2=B116 g ranges. + +2. Device Attributes +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:devi= ceX``, +where X is the IIO index of the device. Under these folders reside a set of +device files, depending on the characteristics and features of the hardware +device in questions. These files are consistently generalized and document= ed in +the IIO ABI documentation. + +The following table shows the ADXL345 related device files, found in the +specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. + ++-------------------------------------------+-----------------------------= -----------------------------+ +| 3-Axis Accelerometer related device files | Description = | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_sampling_frequency | Currently selected sample ra= te. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_sampling_frequency_available | Available sampling frequency= configurations. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_scale | Scale/range for the accelero= meter channels. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_scale_available | Available scale ranges for t= he accelerometer channel. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_x_calibbias | Calibration offset for the X= -axis accelerometer channel. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_x_raw | Raw X-axis accelerometer cha= nnel value. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_y_calibbias | y-axis acceleration offset c= orrection | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_y_raw | Raw Y-axis accelerometer cha= nnel value. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_z_calibbias | Calibration offset for the Z= -axis accelerometer channel. | ++-------------------------------------------+-----------------------------= -----------------------------+ +| in_accel_z_raw | Raw Z-axis accelerometer cha= nnel value. | ++-------------------------------------------+-----------------------------= -----------------------------+ + +Channel Processed Values +------------------------- + +A channel value can be read from its _raw attribute. The value returned is= the +raw value as reported by the devices. To get the processed value of the ch= annel, +apply the following formula: + +.. code-block:: bash + + processed value =3D (_raw + _offset) * _scale + +Where _offset and _scale are device attributes. If no _offset attribute is +present, simply assume its value is 0. + ++-------------------------------------+---------------------------+ +| Channel type | Measurement unit | ++-------------------------------------+---------------------------+ +| Acceleration on X, Y, and Z axis | Meters per second squared | ++-------------------------------------+---------------------------+ + +Sensor Events +------------- + +Particular IIO events will be triggered by the corresponding interrupts. T= he +sensor driver supports no or one active INT line, where the sensor has two +possible INT IOs. Configure the used INT line in the devicetree. If no INT= line +is configured, the sensor falls back to FIFO bypass mode and no events are +possible, only X, Y and Z axis measurements are possible. + +The following table shows the ADXL345 related device files, found in the +specific device folder path ``/sys/bus/iio/devices/iio:deviceX/events``. +Note, the default activity/inactivity is DC coupled. Thus only AC coupled +activity and inactivity are mentioned explicitly. + ++---------------------------------------------+---------------------------= ------------------+ +| Event handle | Description = | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_gesture_doubletap_en | Enable double tap detectio= n on all axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_gesture_doubletap_reset_timeout | Double tap window in [us] = | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_gesture_doubletap_tap2_min_delay | Double tap latent in [us] = | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_gesture_singletap_timeout | Single tap duration in [us= ] | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_gesture_singletap_value | Single tap threshold value= in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_falling_period | Inactivity time in seconds= | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_falling_value | Inactivity threshold value= in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_freefall_en | Enable free-fall detection= on all axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_freefall_period | Free-fall detection time i= n us | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_freefall_value | Free-fall threshold value = in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_referenced_falling_period | AC coupled inactivity time= in seconds | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_referenced_falling_value | AC coupled inactivity thre= shold in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_referenced_rising_value | AC coupled activity thresh= old in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_rising_value | Activity threshold value i= n 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_x_gesture_singletap_en | Enable single tap detectio= n on X axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_x_mag_referenced_rising_en | Enable AC coupled activity= on X axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_x_mag_rising_en | Enable activity detection = on X axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_x&y&z_mag_falling_en | Enable inactivity detectio= n on all axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_x&y&z_mag_referenced_falling_en | Enable AC coupled inactivi= ty on all axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_y_gesture_singletap_en | Enable single tap detectio= n on Y axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_y_mag_referenced_rising_en | Enable AC coupled activity= on Y axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_y_mag_rising_en | Enable activity detection = on Y axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_z_gesture_singletap_en | Enable single tap detectio= n on Z axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_z_mag_referenced_rising_en | Enable AC coupled activity= on Z axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_z_mag_rising_en | Enable activity detection = on Z axis | ++---------------------------------------------+---------------------------= ------------------+ + +Find a detailed description of a particular functionality in the sensor +datasheet. + +Setting the **ODR** explicitly will result in estimated adjusted default v= alues +for the inactivity time detection, where higher frequencies shall default = to +longer wait periods, and vice versa. It is also possible to explicetly +configure inactivity wait times, if the defaulting approach does not match +application requirements. Setting 0 here, will fall back to default settin= g. + +The **g range** configuration also tries to estimate activity and inactivi= ty +thresholds when switching to another g range. The default range will be +factorized by the relation of old range divided by new range. The value ne= ver +becomes 0 and will be at least 1 and at most 255 i.e. 62.5g/LSB according = to +the datasheet. Nevertheless activity and inactivity thresholds can be +overwritten by explicit values. + +When **activity** and **inactivity** events are enabled, the driver automa= tically +will implement its hysteresis solution by setting link bit and autosleep b= it. +The link bit serially links the activity and inactivity functions. On the = other +side, the autosleep function switches the sensor to sleep mode if the +inactivity function is enabled. This will reduce current consumption to the +sub-12.5Hz rate. Inactivity time can be configured between 1s and 255s. Wh= en 0 +is configured as inactivity time, the driver will define a reasonable value +depending on a heuristic approach to optimize power consumption. + +In **DC-coupled** operation, the current acceleration magnitude is compared +directly with THRESH_ACT and THRESH_INACT registers to determine whether +activity or inactivity was detected. In AC-coupled operation for activity +detection, the acceleration value at the start of activity detection is ta= ken +as a reference value. New samples are then compared to this reference valu= e. +Where DC-coupled is the default case detecting against the configured thre= shold, +AC-coupled measurements are referenced against an internal filter depending +on the configured threshold. +Activity detection can be enabled on particular axis. Inactivity detection= on +the other side, is enabled or disabled on all axis. +Note, AC-coupling and DC-coupling are individually set for activity and/or +inactivity detection, and cannot be set both at the same time. Enabling +AC-coupled activity detection, and then DC-coupled activity detection will +result in performing DC-coupled activity detection only. Hence, only the m= ost +recent configuration will valid. + +**Single tap** detection can be configured according to the datasheet by s= pecifying +threshold and duration. If only the single tap is in use, the single tap +interrupt is triggered when the acceleration goes above threshold (i.e. DUR +start) and below the threshold, as long as duration is not exceeded. If si= ngle +tap and double tap are in use, the single tap is triggered when the doulbe= tap +event has been either validated or invalidated. + +For **double tap** configure additionally window and latency in [us]. Late= ncy +starts counting when the single tap goes below threshold and is a waiting +period, any spikes here are ignored for double tap detection. After latenc= y, +the window starts. Any rise above threshold, with a consequent fall below +threshold within window time, rises a double tap signal when going below +threshold. + +Double tap event detection is best described in the datasheet. After a +single tap event was detected, a double tap event can be detected. Therefo= re the +signal must match several criteria, and detection can also considered inva= lid +for three reasons: +* If the **suppress bit** is set and when still in the tap latency period,= any +measurement of acceleration spike above the tap threshold invalidates doub= le tap +detection immediately, i.e. during latency must not occur spikes for doubl= e tap +detection when the suppress bit is set. +* A double tap event is considered invalid, if acceleration lies above the +threshold at the start of the window time for double tap. +* Additionally, double tap detection can be considered invalid, if an +acceleration exceeds the time limit for taps, set by duration register. +Note, since for double tap the same duration counts, i.e. when rising above +threshold, a consequent falling below threshold has to be within duration = time. +Also note, the suppress bit is generally set when double tap is enabled. + +A **free-fall** event is detected if the measurement signal on all axis go= es +below the configured threshold for a configured period of time [us]. It is= then +reissued again and again. The generated magnitude event on the IIO channel= is +actually the same to the DC-coupled inactivity event. Since both can be +considered as magnitude events on all axis (and'd). When using +activity/inactivity detection and free-fall detection, it is probably the = best +approach o combine AC coupled activity/inactivity detection with free-fall. + +In situations with DC coupled activity/inactivity and free-fall enabled, +activity/inactivity indicate the state change of the sensor with far higher +periods [s], than the period taken for free-fall detection [us]. Probably = the +only way would be to verify the state change to inactive of the sensor in = order +to interprete a inactivity event rather than the typically more often happ= ening +free-fall event. + +Note, that activity/inactivy, as also free-fall is recommended for 12.5 Hz= ODR +up to 400 Hz. By the datasheet, free-fall threshold is recommended between= 300mg +and 600mg (0x05 to 0x09), and free-fall time is recommended to be set betw= een +100ms and 350ms (0x14 to 0x46). + +Usage Examples +-------------- + +Show device name: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat name + adxl345 + +Show accelerometer channels value: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw + -1 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw + 2 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw + -253 + +Set calibration offset for accelerometer channels: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias + 0 + + root:/sys/bus/iio/devices/iio:device0> echo 50 > in_accel_x_calibb= ias + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias + 50 + +Given the 13-bit full resolution, the available ranges are calculated by t= he +following forumla: + +.. code-block:: bash + + (g * 2 * 9.80665) / (2^(resolution) - 1) * 100; for g :=3D 2|4|8|16 + +Scale range configuration: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale + 0.478899 + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale_availa= ble + 0.478899 0.957798 1.915595 3.831190 + + root:/sys/bus/iio/devices/iio:device0> echo 1.915595 > ./in_accel_= scale + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale + 1.915595 + +Set output data rate (ODR): + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_sampling_fre= quency + 200.000000 + + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_sampling_fre= quency_available + 0.097000 0.195000 0.390000 0.781000 1.562000 3.125000 6.250000 12.= 500000 25.000000 50.000000 100.000000 200.000000 400.000000 800.000000 1600= .000000 3200.000000 + + root:/sys/bus/iio/devices/iio:device0> echo 1.562000 > ./in_accel_= sampling_frequency + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_sampling_fre= quency + 1.562000 + +Configure one or several events: + +.. code-block:: bash + + root:> cd /sys/bus/iio/devices/iio:device0 + + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./buffer0/in_accel= _x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./buffer0/in_accel= _y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./buffer0/in_accel= _z_en + + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./scan_elements/in= _accel_x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./scan_elements/in= _accel_y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./scan_elements/in= _accel_z_en + + root:/sys/bus/iio/devices/iio:device0> echo 14 > ./in_accel_x_ca= libbias + root:/sys/bus/iio/devices/iio:device0> echo 2 > ./in_accel_y_ca= libbias + root:/sys/bus/iio/devices/iio:device0> echo -250 > ./in_accel_z_ca= libbias + + root:/sys/bus/iio/devices/iio:device0> echo 24 > ./buffer0/length + + ## AC coupled activity, threshold [62.5/LSB] + root:/sys/bus/iio/devices/iio:device0> echo 6 > ./events/in_accel_= mag_referenced_rising_value + + ## AC coupled inactivity, threshold, [62.5/LSB] + root:/sys/bus/iio/devices/iio:device0> echo 4 > ./events/in_accel_= mag_referenced_falling_value + + ## AC coupled inactivity, time [s] + root:/sys/bus/iio/devices/iio:device0> echo 3 > ./events/in_accel_= mag_referenced_falling_period + + ## singletap, threshold + root:/sys/bus/iio/devices/iio:device0> echo 35 > ./events/in_accel= _gesture_singletap_value + + ## singletap, duration [us] + root:/sys/bus/iio/devices/iio:device0> echo 0.001875 > ./events/i= n_accel_gesture_singletap_timeout + + ## doubletap, window [us] + root:/sys/bus/iio/devices/iio:device0> echo 0.025 > ./events/in_ac= cel_gesture_doubletap_reset_timeout + + ## doubletap, latent [us] + root:/sys/bus/iio/devices/iio:device0> echo 0.025 > ./events/in_ac= cel_gesture_doubletap_tap2_min_delay + + ## free-fall, threshold [62.5/LSB] + root:/sys/bus/iio/devices/iio:device0> echo 8 > ./events/in_accel_= mag_freefall_value + + ## free-fall, time [ms] + root:/sys/bus/iio/devices/iio:device0> echo 1.25 > ./events/in_acc= el_mag_freefall_period + + ## activity, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= x_mag_referenced_rising_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= y_mag_referenced_rising_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= z_mag_referenced_rising_en + + ## inactivity, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= x\&y\&z_mag_referenced_falling_en + + ## free-fall, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= mag_freefall_en + + ## singletap, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= x_gesture_singletap_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= y_gesture_singletap_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= z_gesture_singletap_en + + ## doubletap, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= gesture_doubletap_en + +Verify incoming events: + +.. code-block:: bash + + root:# iio_event_monitor adxl345 + Found IIO device with name adxl345 with device number 0 + Event: time: 1739063415957073383, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063415963770218, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063416002563061, type: accel(z), channel: 0, evty= pe: gesture, direction: singletap + Event: time: 1739063426271128739, type: accel(x&y&z), channel: 0, = evtype: mag, direction: falling + Event: time: 1739063436539080713, type: accel(x&y&z), channel: 0, = evtype: mag, direction: falling + Event: time: 1739063438357970381, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063446726161586, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063446727892670, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063446743019768, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063446744650696, type: accel(z), channel: 0, evty= pe: mag, direction: rising + Event: time: 1739063446763559386, type: accel(z), channel: 0, evty= pe: gesture, direction: singletap + Event: time: 1739063448818126480, type: accel(x&y&z), channel: 0, = evtype: mag, direction: falling + ... + +Activity and inactivity belong together and indicate state changes as foll= ows + +.. code-block:: bash + + root:# iio_event_monitor adxl345 + Found IIO device with name adxl345 with device number 0 + Event: time: 1744648001133946293, type: accel(x), channel: 0, evty= pe: mag, direction: rising + + Event: time: 1744648057724775499, type: accel(x&y&z), channel: 0, = evtype: mag, direction: falling + ... + +3. Device Buffers +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver supports IIO buffers. + +All devices support retrieving the raw acceleration and temperature measur= ements +using buffers. + +Usage examples +-------------- + +Select channels for buffer read: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_a= ccel_x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_a= ccel_y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_a= ccel_z_en + +Set the number of samples to be stored in the buffer: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length + +Enable buffer readings: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable + +Obtain buffered data: + +.. code-block:: bash + + root:> iio_readdev -b 16 -s 1024 adxl345 | hexdump -d + WARNING: High-speed mode not enabled + 0000000 00003 00012 00013 00005 00010 00011 00005 = 00011 + 0000010 00013 00004 00012 00011 00003 00012 00014 = 00007 + 0000020 00011 00013 00004 00013 00014 00003 00012 = 00013 + 0000030 00004 00012 00013 00005 00011 00011 00005 = 00012 + 0000040 00014 00005 00012 00014 00004 00010 00012 = 00004 + 0000050 00013 00011 00003 00011 00012 00005 00011 = 00013 + 0000060 00003 00012 00012 00003 00012 00012 00004 = 00012 + 0000070 00012 00003 00013 00013 00003 00013 00012 = 00005 + 0000080 00012 00013 00003 00011 00012 00005 00012 = 00013 + 0000090 00003 00013 00011 00005 00013 00014 00003 = 00012 + 00000a0 00012 00003 00012 00013 00004 00012 00015 = 00004 + 00000b0 00014 00011 00003 00014 00013 00004 00012 = 00011 + 00000c0 00004 00012 00013 00004 00014 00011 00004 = 00013 + 00000d0 00012 00002 00014 00012 00005 00012 00013 = 00005 + 00000e0 00013 00013 00003 00013 00013 00005 00012 = 00013 + 00000f0 00004 00014 00015 00005 00012 00011 00005 = 00012 + ... + +See ``Documentation/iio/iio_devbuf.rst`` for more information about how bu= ffered +data is structured. + +4. IIO Interfacing Tools +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +See ``Documentation/iio/iio_tools.rst`` for the description of the availab= le IIO +interfacing tools. --=20 2.39.5