From nobody Thu Oct 9 00:37:50 2025 Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) (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 2B1AAC2E0; Sun, 22 Jun 2025 15:50:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607420; cv=none; b=AFcLm0dz+VEuDvqAI5YqYRkNlAYFVynTLtGp9J6VkCARxEY41r7jowCgefq1s9CJvatsWBcd2gC9xbRclrakaa/gS3j6ulCXsryjnsSpcUfq7Gh3zJjOhSkAU23Wgwl9qBjy3pBdheX2zrHDkxQ+icVHBLGwdWEqJZBkscipFFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607420; c=relaxed/simple; bh=8JgwxSBZXFoj3NKhuJ2CDWykIX5RT2GyeWaZPnsk7O0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=utDQjscosSDtygMqPmD8Wy++00y+JuivZK9drR6Fo4wvFyVPpNX/1gjpFrTBb+pu13AlLfuGmdd3wiSxDjEJsA+zaBIzpDXRHPXyaW25iQGYG+CLpxe15xjI4g1gFb0JThPt7CKfaBvzLYtjuVRi3BelGQ0FHrqd+rJGeIDftKo= 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=nL9Rc4Cz; arc=none smtp.client-ip=209.85.208.52 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="nL9Rc4Cz" Received: by mail-ed1-f52.google.com with SMTP id 4fb4d7f45d1cf-6089c0d376eso857298a12.2; Sun, 22 Jun 2025 08:50:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607415; x=1751212215; 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=rsk3ey7Q/lVDjbcoHhjW9BfkWYV4mX2YlldODKWQEY8=; b=nL9Rc4CzK1m+C45BreyRtGKHb+XZ+Kqc5io0ng+FOlNDCgWwYkHgUJb/0vZlymOozY kUB8GhWL8nRJuDkvpd2GfHoS1QT/ypR4iY04jN4fk4ppooqne7GteTBW+xUJ6VEkVtYh Md3Sj0uGffu0W5cjSIltEmCNV+jmZHyCw+HFsMRqAg8M6GAmBRTRk6K+4SyMN4PqXL5b Zj639Cn5auMeccGgaezZldB6Phvkq1YstjEmI9ByW/fJ6tPULKvjxGVW3ZGN0NIvgZGP viKadH3ANM+p9Wn9HsBoG7PiMIgpTUC1KVEb+iQFmPeqJRpDhnixAFfyd+F+zwMNoafs dWEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607415; x=1751212215; 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=rsk3ey7Q/lVDjbcoHhjW9BfkWYV4mX2YlldODKWQEY8=; b=p/q0u9a9jbBfOTragoYL/EUTJimM3go/8plA4KJwaWsRei1qSHdLu7eKtSJ5zjYHld KMWYWKvH/V2u6KJXVZTxbcsM0BCwghTsKZwdc37FfSnOChJtPGOadhZ/f7uoVEgu9kaJ LxYu3cIzffLB2moNdMfjlnDiJBm2FYccr6agsgfoVSdOpwz+lytBtOXkG9jJqlGlJJMI s0AOyUTH5cIPAI9wVwk/mfbCg3gee3o2EKasPRoM2Pmkoe7LlmNDM/XwB4zybwag55vZ 0sk8yY8tyj8y97+Unqkb/H8896JFTfqhibWIQPAhnzFcMDSDFwKEiIQB3CrGAl93Wfjg nMyw== X-Forwarded-Encrypted: i=1; AJvYcCVS70Cx/paO6FNMeWQCnD9EBxzJpp4Tp42OXp74K3E22asCikUTlaGRSVmZ9BvZ6y4G2xiUF1k+42KZv0Sj@vger.kernel.org, AJvYcCXYWy76dx5FEQFXXtWsY6cediz0y/F6s+LOSSsX1HbjjB4RerallFtyyhto+MSLZ/095x/UKreaoJc=@vger.kernel.org X-Gm-Message-State: AOJu0YwQko+HYMBqIEtXF7Zhn27HwlTJ+x+/AsLAFjpDrpoLWHN5NeJN nrp89YZi280Q3XXF2ea7VW3dNPV/x6Hnd2gD+COIGmZ0EZOh3sfsCJW6 X-Gm-Gg: ASbGnct6V61A6ajpr7LwIR0l10i6BZfhoYPgcCvJ2PUrxZurG8uc0dSYt2Szn5chJ2I VAtTYcYVGgWtLpRWR6x5F3AZjMTxOaIjn0FE6JbYw+V/6y9Xsc5Ng4w/DK9vzASlJT74h0z3yW+ nY6zJsRJi7B5X0Al8Kgd6hBem+4uHAVJ9HPoth7aYfVmursdhMC/t8BRqNU5iYktSFbosewTpC8 k9t/ADp/YYqesGgC4rlhzCQ+LvpH2MlpOghGxcH4q63o8w3WtAfEeli+FhSXEODSecwahcS61eq //ElxkDoAPPJnBW+MeJ5QMIyUk2Ld/JVX89sQHviw9m4EalMqSoxn+foV7ByA5er3WZO+OAkfKs uO/9NJ7vd5IHZksI7Fd4ztFRF2H5Dt7A+ X-Google-Smtp-Source: AGHT+IFtNx686irHeTeBPbDd+cvGF6IAP7Iwv96BOYOicP1ZCv4uXs0KBIuWcz9X+yX+ovofEEJldw== X-Received: by 2002:a17:906:dc8d:b0:ade:7f2:a17b with SMTP id a640c23a62f3a-ae0578e0010mr310317966b.4.1750607415215; Sun, 22 Jun 2025 08:50:15 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:14 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 1/7] iio: accel: adxl345: simplify interrupt mapping Date: Sun, 22 Jun 2025 15:50:04 +0000 Message-Id: <20250622155010.164451-2-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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" Refactor the sensor interrupt mapping by utilizing regmap_assign_bits(), which accepts a boolean value directly. Introduce a helper function to streamline the identification of the configured interrupt line pin. Also, use identifiers from units.h to represent the full 8-bit register when setting bits. This is a purely refactoring change and does not affect functionality. Signed-off-by: Lothar Rubusch Reviewed-by: Andy Shevchenko --- drivers/iio/accel/adxl345_core.c | 34 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index b60794812738..6c493272a5b0 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -1088,6 +1088,19 @@ static const struct iio_info adxl345_info =3D { .hwfifo_set_watermark =3D adxl345_set_watermark, }; =20 +static int _get_int_line(struct device *dev, int *irq) +{ + *irq =3D fwnode_irq_get_byname(dev_fwnode(dev), "INT1"); + if (*irq > 0) + return ADXL345_INT1; + + *irq =3D fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); + if (*irq > 0) + return ADXL345_INT2; + + return ADXL345_INT_NONE; +} + /** * adxl345_core_probe() - Probe and setup for the accelerometer. * @dev: Driver model representation of the device @@ -1203,23 +1216,16 @@ int adxl345_core_probe(struct device *dev, struct r= egmap *regmap, if (ret) return ret; =20 - irq =3D fwnode_irq_get_byname(dev_fwnode(dev), "INT1"); - if (irq < 0) { - intio =3D ADXL345_INT2; - irq =3D fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); - if (irq < 0) - intio =3D ADXL345_INT_NONE; - } - + intio =3D _get_int_line(dev, &irq); if (intio !=3D ADXL345_INT_NONE) { /* - * Any bits set to 0 in the INT map register send their respective - * interrupts to the INT1 pin, whereas bits set to 1 send their respecti= ve - * interrupts to the INT2 pin. The intio shall convert this accordingly. + * In the INT map register, bits set to 0 route their + * corresponding interrupts to the INT1 pin, while bits set to 1 + * route them to the INT2 pin. The intio should handle this + * mapping accordingly. */ - regval =3D intio ? 0xff : 0; - - ret =3D regmap_write(st->regmap, ADXL345_REG_INT_MAP, regval); + ret =3D regmap_assign_bits(st->regmap, ADXL345_REG_INT_MAP, + U8_MAX, intio); if (ret) return ret; =20 --=20 2.39.5 From nobody Thu Oct 9 00:37:50 2025 Received: from mail-ed1-f53.google.com (mail-ed1-f53.google.com [209.85.208.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 2B9B01AF0C8; Sun, 22 Jun 2025 15:50:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607419; cv=none; b=eXhz5FYsUU9OIjrlIwzRvlVXwb4TT/WO3tcgq/ThSMto0TU/l1MJdNwVprlsoWyvQO1QEXl9aDGIKacDg8V5QTbPA5DC6Cozogw2oLv0OjtTjYqHqiuTl2ruGhsKMGWf3fMOt6UstbBF6B60bJZlCxYUhGKE1rTdViGdFCpn+ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607419; c=relaxed/simple; bh=ydgCnLipKVTUj6twIc8q705fS0jiwcTDmecnkO84tUw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=KfvrSlHUIbd57UIM1CgRt/mjUTDS6qdt0X8q6l5er3iL4zVYvvAnoDJvzFTC/nWNl/xqzYkZ5TxniS7+tkZmWhxEkdJNnhd7sEPLP7U87shXiV2htfGNBNZm7wcdrtQdcrhWTEnznD+rKOMviDzITFQ6HcPzxaZPgL9j8p6bsHY= 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=HIC1POCJ; arc=none smtp.client-ip=209.85.208.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="HIC1POCJ" Received: by mail-ed1-f53.google.com with SMTP id 4fb4d7f45d1cf-606b39b19b6so746845a12.1; Sun, 22 Jun 2025 08:50:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607416; x=1751212216; 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=86cTLjMIiPRxzeY6qqdXZaoqO74rsoMKFoqJkm2eOc0=; b=HIC1POCJdBWCaI1sAaJzzmqhNyfab+3ga9bT4dkBqIooPiV9bokXjvOK2QDgM4rexg pRyrfOqXvNH+U+0i3wYPMfH53DmkKwZtZy+6tCoJLswoLGILoG2gyjXm3tI9O9bVbxFT XgZFMfPdAR/J/7KWI9VrtlOFmmn+dNz9/aLRRk2T/YXtCd9PSJcWdawntvVGIGw+4QBh Po1uM+Zc+4LMqU1WUFYtBZuQ7cSRM9uGapi9yrIzUuJXLPpzvY3fsHGSx+m+hCimm5q2 C4dIYPduZehzb1zQvIFQMelRT9MTl2rhXDHRb/V4USG82wXnouOZrav8nZuHcT0YCE+s V+Pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607416; x=1751212216; 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=86cTLjMIiPRxzeY6qqdXZaoqO74rsoMKFoqJkm2eOc0=; b=uDAjemPo2QTOeZc1uVl47lWF7KCE4ahSyXwStGKOgfVPHOk9jvB5raCU/NxmwlTL2d n4k2hjdCct1tl+KRGcnHvfQ9sKnIt4NALrhc578blly2WeTHymy6CaISEcyi5lIEIXiJ +YqBmlpLwYmkp2Arzj+ghAHybGC9C6W7iFueEanISDgT0KdUU3+WWVT3lBDnQ0kJGIgu WFW+Rpbsv3lnNZN7Bun0FVmxyV67ORq5sMc7KbFCIeXJDExbUnLM9fDT1O8ieedE7tWz vEzTt85RxVS6RdO406dXggYMgI07tBNXQhbgDSAd31svlY2iW0eHRMPvtarHmweAxC8h WXuw== X-Forwarded-Encrypted: i=1; AJvYcCU9IwrPDD7umuCL4qj179jScZEYpGYUUflinVAGdmSO4kMadQWLgPhHumzwg1GgklkD6Zp/dlhJ3g4=@vger.kernel.org, AJvYcCW8Bq9AgZuZ7gcYiXzlcD0HcEgjzFG0vpyXRzD7u5p7pYNUMsb15uSQBoihkDuHaVkqdPasPiflNw3TARk1@vger.kernel.org X-Gm-Message-State: AOJu0Yzhg6//EJ3coIIwPh4VUI03WUMhhpoLThoYw27chtz9F6FH8/ET mOK+6kF2H05lnOrR5YMr4Moh9hRq3V+BO1ZP80RTDSPCSrzfsdRMzhKO X-Gm-Gg: ASbGncv5vhTBR0QkXDdFmEwOcHnx9WDiSpGGYZvL+tw/sumYUPtA28m6BpFXzldtUX2 IXiO3fBuoRalKI/+ddya3IqfJMVOnuJpM/pYgavheezeVjca0VEIgkflZh9uBwW4yEYgbWpp+Cd vfC+kgk2yLWD6yrhYToDQu1A14+GRsqShlr84ZP1G+CbCuJyGXZ8rE7Q36vYesCUoRh0JYcRlBT edLsd5lm9HCphiW82usNEbzbXDmhaMyGRDLLX2jkDSVmN6G6un14th79CyLb1DuNj8R4BE+iMOa ruEw7QtveX1D/1OBwnqSokHSf+ovrSdNf43gWdwGzEAtVP8b3FpfP+TYpBsXhTKBWxY518+v8gg JJo+kJ1X8eEPLh4bWeubMT1cRCrkcLuLI X-Google-Smtp-Source: AGHT+IGQY9fkS1+Z+xDeRFps+Oef+vuNDVKW5BXKo7lx2nmKqtM7xXAjbnrfSXJM6nCo/YBwJiCxMw== X-Received: by 2002:a17:907:e2e2:b0:ad8:a2d0:8f8a with SMTP id a640c23a62f3a-ae057b9a320mr282676066b.16.1750607416299; Sun, 22 Jun 2025 08:50:16 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:15 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 2/7] iio: accel: adxl345: simplify reading the FIFO Date: Sun, 22 Jun 2025 15:50:05 +0000 Message-Id: <20250622155010.164451-3-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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" Bulk FIFO reading can be streamlined by eliminating redundant variables and simplifying the process of reading x-, y-, and z-axis measurement sets. This is a refactoring change with no expected impact on functionality. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index 6c493272a5b0..3821fe7cf2a0 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -885,15 +885,12 @@ static int adxl345_get_samples(struct adxl345_state *= st) */ static int adxl345_fifo_transfer(struct adxl345_state *st, int samples) { - size_t count; int i, ret =3D 0; =20 - /* count is the 3x the fifo_buf element size, hence 6B */ - count =3D sizeof(st->fifo_buf[0]) * ADXL345_DIRS; for (i =3D 0; i < samples; i++) { - /* read 3x 2 byte elements from base address into next fifo_buf position= */ ret =3D regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE, - st->fifo_buf + (i * count / 2), count); + st->fifo_buf + (i * ADXL345_DIRS), + sizeof(st->fifo_buf[0]) * ADXL345_DIRS); if (ret) return ret; =20 --=20 2.39.5 From nobody Thu Oct 9 00:37:50 2025 Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.42]) (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 45E171F09B3; Sun, 22 Jun 2025 15:50:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607421; cv=none; b=iWpqezheOOk8EHwLP89PI7+sxw2rb70q03y5dz8KzeB2YllrX2lfb4sEOTCx/tfApwjNejPCtIeT/jcY4osT7d4H5TZqxewz/14GRNNa1gbCqv7yiXDVEQwi3jNKza+1vfju2C4umANCHSXGM7jQ5+GVqYwWPSIu+XK3kP5x8/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607421; c=relaxed/simple; bh=oCRy1ZQSUb9ukwEP/W3QHY4woZ1eiV+QRQuJ/xo/CUY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DlMCMtx3y5cEhQoF7gzPFUmMUAZw0zNdzCyOV3/yS9i1sO9GOQTv7+PNK1Tsr/sme9B8bDkWSArJ5n2bFjpzdN7MTPXT507SSa0rjfZ2CoOils+R+F1ch+1V8nuWYcxWbbZLi3PFr8r9rmH1WUneHmJgfmCUul3xhmBZTF7/s6M= 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=SYggceU4; arc=none smtp.client-ip=209.85.218.42 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="SYggceU4" Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-ade6ef7e6b5so63570866b.3; Sun, 22 Jun 2025 08:50:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607418; x=1751212218; 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=gQb7325VOJ6/baYGlSu5wu/ewUw5736k+prFnTlHKuw=; b=SYggceU4AD+JO3ngNu8Ol54lwuAqL0vKO2W1qH40DzCyLq7RgSbjmzeLHJLQGl1pf0 56NUPB/7alq/J3aa3vKEejv1im2q5HFAR3p18DRMVux5FNqqYRIkjQM0mT9189EnYQUC QrARiA0xvcdDbTJtS2ShUJaR101NbmyNj2AT0b4ewpWAR6i3x3fVh9sqBnmpuL9lcseO 84+kJNSwq7GVE1sg3a5U1/xFPHIWF9i8gH5hbU8jFK68JUtvlPddjX/FfrGrSMfSbMZM eQ3Hyrm9X/WWopIKDQAdYAeL8i6+h4U/x1dZ+A3RR1lJoJgj28fW4qbxJwgOqO4vOYX7 8iow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607418; x=1751212218; 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=gQb7325VOJ6/baYGlSu5wu/ewUw5736k+prFnTlHKuw=; b=RJcizTT63fSRpjDXTCK+G8hbj41/OJSMbm9jQNzsJn7ER+9Ax6yzUP6h7BAkqfHLsk rna0C+sdKAc8QpIond9WTNjKTxfm6fuMInx76fY9edEiRVop0am6qLP9crctmOsFHBVb IPzaiS80x4IaRvOdnqgOx0WW2/HHwzPrc+AFg/miafxyzi9WsYctpkSoDyLm/KuFAWOB DBMfw80oG1Q1TJgNhbkBSg9HBuafP87zqIR3edMkX0KkJpJrUAMo/sJZ506qeb7A0gG5 DDn7YXU8JEtLUqUaKfBXh9yZLqUuNqSimgcYrwB43JydqyYpm5vnC2gRfxo9XvDi1ER8 JGgA== X-Forwarded-Encrypted: i=1; AJvYcCVRHl/kTIGiQfCxQp4EwBgLVRMWRua4XnykrMBInhoBJrqBluPgwf9Gbhl+CQIVXBsS35EU6+K2uO4=@vger.kernel.org, AJvYcCX7/3bpipsuRmf4r1kVdTwUwtxhhyuAurFnmPPkkH+DilncrQ/33yabH+wMRRbbQjtRnkxCmXGD73xXvT90@vger.kernel.org X-Gm-Message-State: AOJu0YyMswDmpRhNM+deS05XY110dj/JClEFUazPljvgLu6izmQ3VH9D EhuvG8JzSudcrhBG8phEBdyluhHFUhvX4SEAnCgAyyKYHXSgbi2wbysY X-Gm-Gg: ASbGncvzYjd4VHFZA/BlcDI/r/7uE3OgERwzRjdm9RMp+lrnlC6+JazyQ1A3X/6h5MQ 3eDlzMBE+0ux+s+gyOYYpdv+M19iz9blzqT4FoopEQJIc+J86l5gR6oWQL8xe+Ix+3ugRkMDiPn KIOqdc0bP8Uw9StyRyU3CSCmkOKWQEpoQ7OTqgtz4ALWXlr63z+1E8AnXJQk9vrqDlSs8BVMx/f PB9UWPQwJETKEyasfzHULZQ5nYnTVHgqyV/1LXW40sx9jqEjNjvvXDK8Y5OuhjwlBImNiKPG9n3 vsJ3fykh8QvkZwmIjLrjnKFwWBg8j29CdCzHMZwz632eJC1LbwhLhjvU3yXTje2XxpMa+wQ8F1o W6vcCORN3xYOVyk6twUH4Vo0GEzJto3nx X-Google-Smtp-Source: AGHT+IHuLR8UlCApY770GdUmnFg6F2+tFx5EhjlpaG7j68rvbck6zMl00E0MtP/HtFjemga1lShBOw== X-Received: by 2002:a17:907:7213:b0:ad8:89c7:61e2 with SMTP id a640c23a62f3a-ae05794689dmr321931166b.8.1750607417391; Sun, 22 Jun 2025 08:50:17 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:16 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 3/7] iio: accel: adxl345: add activity event feature Date: Sun, 22 Jun 2025 15:50:06 +0000 Message-Id: <20250622155010.164451-4-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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" Enable the sensor to detect activity and trigger interrupts accordingly. Activity events are determined based on a threshold, which is initialized to a sensible default during probe. This default value is adopted from the legacy ADXL345 input driver to maintain consistent behavior. The combination of activity detection, ODR configuration, and range settings lays the groundwork for the activity/inactivity hysteresis mechanism, which will be implemented in a subsequent patch. As such, portions of this patch prepare switch-case structures to support those upcoming changes. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 244 ++++++++++++++++++++++++++++++- 1 file changed, 241 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index 3821fe7cf2a0..99b590e67967 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, @@ -144,6 +162,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_shared_by_type =3D BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE), + }, { /* single tap */ .type =3D IIO_EV_TYPE_GESTURE, @@ -237,6 +262,90 @@ static int adxl345_set_measure_en(struct adxl345_state= *st, bool en) ADXL345_POWER_CTL_MEASURE, en); } =20 +/* activity / inactivity */ + +static int adxl345_is_act_inact_en(struct adxl345_state *st, + enum adxl345_activity_type type) +{ + unsigned int axis_ctrl; + unsigned int regval; + bool en; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl); + if (ret) + return ret; + + /* Check if axis for activity are enabled */ + switch (type) { + case ADXL345_ACTIVITY: + en =3D FIELD_GET(ADXL345_ACT_X_EN, axis_ctrl) | + FIELD_GET(ADXL345_ACT_Y_EN, axis_ctrl) | + FIELD_GET(ADXL345_ACT_Z_EN, axis_ctrl); + if (!en) + return false; + break; + default: + return -EINVAL; + } + + /* Check if specific interrupt is enabled */ + ret =3D regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val); + if (ret) + return ret; + + return adxl345_act_int_reg[type] & regval; +} + +static int adxl345_set_act_inact_en(struct adxl345_state *st, + enum adxl345_activity_type type, + bool cmd_en) +{ + unsigned int axis_ctrl; + unsigned int threshold; + int ret; + + if (cmd_en) { + /* When turning on, check if threshold is valid */ + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[type], + &threshold); + if (ret) + return ret; + + if (!threshold) /* Just ignore the command if threshold is 0 */ + return 0; + } + + /* Start modifying configuration registers */ + ret =3D adxl345_set_measure_en(st, false); + if (ret) + return ret; + + /* Enable axis according to the command */ + switch (type) { + case ADXL345_ACTIVITY: + axis_ctrl =3D ADXL345_ACT_X_EN | ADXL345_ACT_Y_EN | + ADXL345_ACT_Z_EN; + break; + default: + return -EINVAL; + } + + ret =3D regmap_assign_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL, + axis_ctrl, cmd_en); + if (ret) + return ret; + + /* Enable the interrupt line, according to the command */ + ret =3D regmap_assign_bits(st->regmap, ADXL345_REG_INT_ENABLE, + adxl345_act_int_reg[type], cmd_en); + if (ret) + return ret; + + return adxl345_set_measure_en(st, true); +} + /* tap */ =20 static int _adxl345_set_tap_int(struct adxl345_state *st, @@ -624,6 +733,31 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, return adxl345_set_measure_en(st, true); } =20 +static int adxl345_read_mag_config(struct adxl345_state *st, + enum iio_event_direction dir, + enum adxl345_activity_type type_act) +{ + switch (dir) { + case IIO_EV_DIR_RISING: + return !!adxl345_is_act_inact_en(st, type_act); + default: + return -EINVAL; + } +} + +static int adxl345_write_mag_config(struct adxl345_state *st, + enum iio_event_direction dir, + enum adxl345_activity_type type_act, + bool state) +{ + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl345_set_act_inact_en(st, type_act, state); + default: + return -EINVAL; + } +} + static int adxl345_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -634,6 +768,9 @@ static int adxl345_read_event_config(struct iio_dev *in= dio_dev, int ret; =20 switch (type) { + case IIO_EV_TYPE_MAG: + return adxl345_read_mag_config(st, dir, + ADXL345_ACTIVITY); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -665,6 +802,10 @@ 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: + return adxl345_write_mag_config(st, dir, + ADXL345_ACTIVITY, + state); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -679,6 +820,58 @@ static int adxl345_write_event_config(struct iio_dev *= indio_dev, } } =20 +static int adxl345_read_mag_value(struct adxl345_state *st, + enum iio_event_direction dir, + enum iio_event_info info, + enum adxl345_activity_type type_act, + int *val, int *val2) +{ + unsigned int threshold; + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[type_act], + &threshold); + if (ret) + return ret; + *val =3D 62500 * threshold; + *val2 =3D MICRO; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_write_mag_value(struct adxl345_state *st, + enum iio_event_direction dir, + enum iio_event_info info, + enum adxl345_activity_type type_act, + int val, int val2) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + /* Scaling factor 62.5mg/LSB, i.e. ~16g corresponds to 0xff */ + val =3D DIV_ROUND_CLOSEST(val * MICRO + val2, 62500); + switch (dir) { + case IIO_EV_DIR_RISING: + return regmap_write(st->regmap, + adxl345_act_thresh_reg[type_act], + val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + static int adxl345_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -691,6 +884,10 @@ static int adxl345_read_event_value(struct iio_dev *in= dio_dev, int ret; =20 switch (type) { + case IIO_EV_TYPE_MAG: + return adxl345_read_mag_value(st, dir, info, + ADXL345_ACTIVITY, + val, val2); case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -741,6 +938,13 @@ static int adxl345_write_event_value(struct iio_dev *i= ndio_dev, return ret; =20 switch (type) { + case IIO_EV_TYPE_MAG: + ret =3D adxl345_write_mag_value(st, dir, info, + ADXL345_ACTIVITY, + val, val2); + if (ret) + return ret; + break; case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -980,7 +1184,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); @@ -1007,6 +1212,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) @@ -1034,6 +1249,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; @@ -1042,7 +1258,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; @@ -1053,12 +1270,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)) @@ -1226,6 +1450,20 @@ int adxl345_core_probe(struct device *dev, struct re= gmap *regmap, if (ret) return ret; =20 + /* + * Initialized with sensible default values to streamline + * sensor operation. These defaults are partly derived from + * the previous input driver for the ADXL345 and partly + * based on the recommendations provided 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 Thu Oct 9 00:37:50 2025 Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.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 57F021F4621; Sun, 22 Jun 2025 15:50:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607422; cv=none; b=slyRzpV5kADCmf/MeEp9zbsrkJzQUVeMP9YuWyM+bpqWLTWBwghaV7R590X+h/EzFulwlZ2kDo8iiWm4WSZ1DCWMBH67MGh7/6UzE26BTsJLMmjkZIXtwkejZ80m6Dcw5MxGy78XQkoEVRL3zCEOTxI9ljlq0Ut82EtxJIU0YxU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607422; c=relaxed/simple; bh=cx/nfTUB2f+1sh1owG+x/MWH2zcuedAq36k/fbXL95U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=AN0gAOgGbMYAA3Bc/07Dx7ZVDOjV7fGq7gPRbXmNfUf+17L6kpvGI0ViXrxuq2pQzS54RGuhLJTd9klVPeRcpqPhWNeq3JogQvLmiyb4uB+KQWG9qX1HHKCqYPjMJDEzC+jsNtZxvpZfuihwvwe4Trie/KdbB9kvYTBDTVv4gQ0= 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=B4cBpT1i; arc=none smtp.client-ip=209.85.208.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="B4cBpT1i" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-6095f07cd53so676910a12.3; Sun, 22 Jun 2025 08:50:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607419; x=1751212219; 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=KsIAHZTI45ZQdSlwPvHH3Qj1U4OpAFgZYtBorM87rNk=; b=B4cBpT1iwHbRHFsN2ceFhPZB7OLt8ZyxdY66IYgjIcMknc2T36429g7aPALi2E4zOR dE6NSY2YwoYYqEhH5vMyH2g71OSfnl3t79AidMiVoVX3+5WhFFrnOrYR7U8iVmD5VeMG tm3eFvAJvUWE7LVnmaxxePjdXQEdOKxtWzPMx9kk80+TuAIIAs+VtWTusWMQdl1LOVCo k7K3dodbKZxTEmzUQ/ymBjVC7fwv0ZZLtuUuTQTaavC8LKT8vCNPhrmWUnxKXszbHTCF eC+bVDi3PYklF5U8AS2dLpWBKQ/QQYHXUgS44dWo2ntHkt+iJAwE8kZmoAZ8OwFQcRFM v4dA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607419; x=1751212219; 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=KsIAHZTI45ZQdSlwPvHH3Qj1U4OpAFgZYtBorM87rNk=; b=l5H7iJ88JiJHIw91d82aPoVO/yxvHTzIcOaznTikbqZa33LEYewB+dLY5y++KwYqvJ 1L8XCX23E+PAB8jrAa56iOehQPGvYINP3ChQRMSjtZU2vQP4G9wyqWUDw/hXo5sTZCqn BoBctAFbx/gfCYewLtZgAJnMRsuPX+xjYg6Nw7VgZI/z2f0unjhFRlQ+n5NkSXVWXN48 J8kXcS7ppHrknwfvqiNMpJ1/NghX8UXYlZa9InEns+qH+KfoxgQDc1uKxDh5iewurHTE a3RXpqpp7wgpUUQ2GawLeMnqjMiEmHNebHoyzNn32F1j+2vi49HENjR6R5ATWZPKYVj8 Vqiw== X-Forwarded-Encrypted: i=1; AJvYcCUGdglZXX2ldjDBejaYeRSQUCVUq2TcGSWmqGzBEFWS63bI+O8b1yyS3WSlScmYbFXcOomBDMzkoALRNfsM@vger.kernel.org, AJvYcCUadsLORb7JFNP0WtQffjv8lwX4wEgb2Nrn3+ZdH1bSmDvLL7LicnUy72qyZcAn1Rosj0RDo+lEi1w=@vger.kernel.org X-Gm-Message-State: AOJu0YzJY2NcOjzfS757ZjA7FPNCWLzVJ/6bte3aZVVt2MBIoLY6J6gH rdN/984s4svrBImG86E4KLkK5vqWN1278nQ5lmJCO7ML2L4+ItBFFCbv X-Gm-Gg: ASbGnctu+LLwiJsCd0Sy7/DX4yrkD94VaYSED8WFTrhxpBBa3B4t9NBuL2b1Z2rG1px ZYsFrB8HbP660AurbxS2cOpoUeIxlgmrEyqcPTE7ExDF5Fompq866/nqpNMET4qmBJLSyCIUlng zXDAFs/+btetoSuA66odIzd96NoVbjuymJUH+RgVm+EriKybouqgsBWcnrD3+IdiYb9fMbfR2Ft f6rHBfkpQBDsY/88R6lO7mV1CVP+zK9Q38ZmM8T55cDTuTzL8sSI86W/LAdF+GHTfNSBR+wtdQx 5qyWm4kAVpHxVZ9wedm5EVDdW9zVeN1+EABKsZYwxbo7B4ID0j4tYDC+yofsP/A/1X77ap4gdGJ CQdicn66LmLrCiA186QGv7S8RFZNh3epb X-Google-Smtp-Source: AGHT+IGQLw0b7XG1xtw2s9ubCrwCns/JizWuQBLgEQwVAZLnAk0jw0JGz2MKgsnBMXqxEj7ZjE1GcA== X-Received: by 2002:a17:906:c152:b0:ad8:8e05:e5e9 with SMTP id a640c23a62f3a-ae0578959d4mr354785866b.2.1750607418529; Sun, 22 Jun 2025 08:50:18 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:18 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 4/7] iio: accel: adxl345: add inactivity feature Date: Sun, 22 Jun 2025 15:50:07 +0000 Message-Id: <20250622155010.164451-5-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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 Add support for the sensor=E2=80=99s inactivity feature in the driver. When= both activity and inactivity detection are enabled, the sensor sets a link bit that ties the two functions together. This also enables auto-sleep mode, allowing the sensor to automatically enter sleep state upon detecting inactivity. Inactivity detection relies on a configurable threshold and a specified time period. If sensor measurements remain below the threshold for the defined duration, the sensor transitions to the inactivity state. When an Output Data Rate (ODR) is set, the inactivity time period is automatically adjusted to a sensible default. Higher ODRs result in shorter inactivity timeouts, while lower ODRs allow longer durations-within reasonable upper and lower bounds. This is important because features like auto-sleep operate effectively only between 12.5 Hz and 400 Hz. These defaults are applied when the sample rate is modified, but users can override them by explicitly setting a custom inactivity timeout. Similarly, configuring the g-range provides default threshold values for both activity and inactivity detection. These are implicit defaults meant to simplify configuration, but they can also be manually overridden as needed. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 240 ++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index 99b590e67967..3faf1af013c7 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 { @@ -147,6 +156,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; @@ -213,10 +230,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 { @@ -264,6 +300,52 @@ static int adxl345_set_measure_en(struct adxl345_state= *st, bool en) =20 /* activity / inactivity */ =20 +/** + * adxl345_set_inact_time - Configure inactivity time explicitly or by ODR. + * @st: The sensor state instance. + * @val_s: A desired time value, between 0 and 255. + * + * Inactivity time can be configured between 1 and 255 seconds. If a user = sets + * val_s to 0, a default inactivity time is calculated automatically (sinc= e 0 is + * also invalid and undefined by the sensor). + * + * In such cases, power consumption should be considered: the inactivity p= eriod + * should be shorter at higher sampling frequencies and longer at lower on= es. + * Specifically, for frequencies above 255 Hz, the default is set to 10 se= conds; + * for frequencies below 10 Hz, it defaults to 255 seconds. + * + * The calculation method subtracts the integer part of the configured sam= ple + * frequency from 255 to estimate the inactivity time in seconds. Sub-Hertz + * values are ignored in this approximation. Since the recommended output = data + * rates (ODRs) for features like activity/inactivity detection, sleep mod= es, + * and free fall range between 12.5 Hz and 400 Hz, frequencies outside this + * range will either use the defined boundary defaults or require explicit + * configuration via val_s. + * + * Return: 0 or error value. + */ +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s) +{ + int max_boundary =3D U8_MAX; + int min_boundary =3D 10; + unsigned int val =3D min(val_s, U8_MAX); + 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 clamp(max_boundary - adxl345_odr_tbl[odr][0], + min_boundary, max_boundary); + } + + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); +} + static int adxl345_is_act_inact_en(struct adxl345_state *st, enum adxl345_activity_type type) { @@ -285,6 +367,13 @@ static int adxl345_is_act_inact_en(struct adxl345_stat= e *st, if (!en) return false; break; + case ADXL345_INACTIVITY: + en =3D FIELD_GET(ADXL345_INACT_X_EN, axis_ctrl) | + FIELD_GET(ADXL345_INACT_Y_EN, axis_ctrl) | + FIELD_GET(ADXL345_INACT_Z_EN, axis_ctrl); + if (!en) + return false; + break; default: return -EINVAL; } @@ -297,12 +386,32 @@ static int adxl345_is_act_inact_en(struct adxl345_sta= te *st, return adxl345_act_int_reg[type] & regval; } =20 +static int adxl345_set_act_inact_linkbit(struct adxl345_state *st, + enum adxl345_activity_type type, + bool en) +{ + int act_en, inact_en; + + act_en =3D adxl345_is_act_inact_en(st, ADXL345_ACTIVITY); + if (act_en < 0) + return act_en; + + inact_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); + if (inact_en < 0) + return inact_en; + + return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_INACT_MSK, + en && act_en && inact_en); +} + static int adxl345_set_act_inact_en(struct adxl345_state *st, enum adxl345_activity_type type, bool cmd_en) { unsigned int axis_ctrl; unsigned int threshold; + unsigned int period; int ret; =20 if (cmd_en) { @@ -315,6 +424,18 @@ static int adxl345_set_act_inact_en(struct adxl345_sta= te *st, =20 if (!threshold) /* Just ignore the command if threshold is 0 */ return 0; + + /* When turning on inactivity, check if inact time is valid */ + if (type =3D=3D ADXL345_INACTIVITY) { + ret =3D regmap_read(st->regmap, + ADXL345_REG_TIME_INACT, + &period); + if (ret) + return ret; + + if (!period) + return 0; + } } =20 /* Start modifying configuration registers */ @@ -328,6 +449,10 @@ static int adxl345_set_act_inact_en(struct adxl345_sta= te *st, axis_ctrl =3D ADXL345_ACT_X_EN | ADXL345_ACT_Y_EN | ADXL345_ACT_Z_EN; break; + case ADXL345_INACTIVITY: + axis_ctrl =3D ADXL345_INACT_X_EN | ADXL345_INACT_Y_EN | + ADXL345_INACT_Z_EN; + break; default: return -EINVAL; } @@ -343,6 +468,11 @@ static int adxl345_set_act_inact_en(struct adxl345_sta= te *st, if (ret) return ret; =20 + /* Set link-bit and auto-sleep only when ACT and INACT are enabled */ + ret =3D adxl345_set_act_inact_linkbit(st, type, cmd_en); + if (ret) + return ret; + return adxl345_set_measure_en(st, true); } =20 @@ -575,9 +705,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(st, 0); } =20 static int adxl345_find_range(struct adxl345_state *st, int val, int val2, @@ -598,9 +735,49 @@ 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(U8_MAX, max(1, act_threshold)); + + inact_threshold =3D inact_threshold * adxl345_range_factor_tbl[range_old] + / adxl345_range_factor_tbl[range]; + inact_threshold =3D min(U8_MAX, 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, @@ -735,11 +912,14 @@ static int adxl345_write_raw(struct iio_dev *indio_de= v, =20 static int adxl345_read_mag_config(struct adxl345_state *st, enum iio_event_direction dir, - enum adxl345_activity_type type_act) + enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact) { switch (dir) { case IIO_EV_DIR_RISING: return !!adxl345_is_act_inact_en(st, type_act); + case IIO_EV_DIR_FALLING: + return !!adxl345_is_act_inact_en(st, type_inact); default: return -EINVAL; } @@ -748,11 +928,14 @@ static int adxl345_read_mag_config(struct adxl345_sta= te *st, static int adxl345_write_mag_config(struct adxl345_state *st, enum iio_event_direction dir, enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact, bool state) { switch (dir) { case IIO_EV_DIR_RISING: return adxl345_set_act_inact_en(st, type_act, state); + case IIO_EV_DIR_FALLING: + return adxl345_set_act_inact_en(st, type_inact, state); default: return -EINVAL; } @@ -770,7 +953,8 @@ static int adxl345_read_event_config(struct iio_dev *in= dio_dev, switch (type) { case IIO_EV_TYPE_MAG: return adxl345_read_mag_config(st, dir, - ADXL345_ACTIVITY); + ADXL345_ACTIVITY, + ADXL345_INACTIVITY); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -805,6 +989,7 @@ static int adxl345_write_event_config(struct iio_dev *i= ndio_dev, case IIO_EV_TYPE_MAG: return adxl345_write_mag_config(st, dir, ADXL345_ACTIVITY, + ADXL345_INACTIVITY, state); case IIO_EV_TYPE_GESTURE: switch (dir) { @@ -824,9 +1009,11 @@ static int adxl345_read_mag_value(struct adxl345_stat= e *st, enum iio_event_direction dir, enum iio_event_info info, enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact, int *val, int *val2) { unsigned int threshold; + unsigned int period; int ret; =20 switch (info) { @@ -841,9 +1028,26 @@ static int adxl345_read_mag_value(struct adxl345_stat= e *st, *val =3D 62500 * threshold; *val2 =3D MICRO; return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[type_inact], + &threshold); + if (ret) + return ret; + *val =3D 62500 * threshold; + *val2 =3D MICRO; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } + case IIO_EV_INFO_PERIOD: + ret =3D regmap_read(st->regmap, + ADXL345_REG_TIME_INACT, + &period); + if (ret) + return ret; + *val =3D period; + return IIO_VAL_INT; default: return -EINVAL; } @@ -853,6 +1057,7 @@ static int adxl345_write_mag_value(struct adxl345_stat= e *st, enum iio_event_direction dir, enum iio_event_info info, enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact, int val, int val2) { switch (info) { @@ -864,9 +1069,15 @@ static int adxl345_write_mag_value(struct adxl345_sta= te *st, return regmap_write(st->regmap, adxl345_act_thresh_reg[type_act], val); + case IIO_EV_DIR_FALLING: + return regmap_write(st->regmap, + adxl345_act_thresh_reg[type_inact], + val); default: return -EINVAL; } + case IIO_EV_INFO_PERIOD: + return adxl345_set_inact_time(st, val); default: return -EINVAL; } @@ -887,6 +1098,7 @@ static int adxl345_read_event_value(struct iio_dev *in= dio_dev, case IIO_EV_TYPE_MAG: return adxl345_read_mag_value(st, dir, info, ADXL345_ACTIVITY, + ADXL345_INACTIVITY, val, val2); case IIO_EV_TYPE_GESTURE: switch (info) { @@ -941,6 +1153,7 @@ static int adxl345_write_event_value(struct iio_dev *i= ndio_dev, case IIO_EV_TYPE_MAG: ret =3D adxl345_write_mag_value(st, dir, info, ADXL345_ACTIVITY, + ADXL345_INACTIVITY, val, val2); if (ret) return ret; @@ -1222,6 +1435,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) @@ -1460,10 +1684,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, 0x37); + 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 Thu Oct 9 00:37:50 2025 Received: from mail-ed1-f41.google.com (mail-ed1-f41.google.com [209.85.208.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 6382C1F560B; Sun, 22 Jun 2025 15:50:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607423; cv=none; b=WsVEI/AqT6hdeN+qpwd10FFptWm9xNLMsKNhEj+nYeLHtBGknTrHfJ+aOMis3TJTgC6rmkeztIRaRvpzMAx4zUktNZT+vCqtJOJ3/Me4ptiFaWienvZkS6uplTt0lSgpG0+gbJOFC7jspuE9yryooMA9sx+3T1GtAHziTlQyKEU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607423; c=relaxed/simple; bh=5q4vaZJIwBeMq0b5T8uy5ma589RluGjH1eJbp7aiXc8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rZrNtvPciopKjig3YhE4aac7xvSCJHYP9FyV8gccP5ZR6DEpvVB1qHADj4z7Hj61yt6jdjsmszJXz7kRr/MbEl897vJCgI+OvifveeFXBYugVqR5axUTlqQlpK3+35+EeqdFAwhKUCtd9tQfagHPI0fenV/T62c72faaDSS9Lv0= 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=WJV0fRY6; arc=none smtp.client-ip=209.85.208.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="WJV0fRY6" Received: by mail-ed1-f41.google.com with SMTP id 4fb4d7f45d1cf-6095cea1f4eso269182a12.0; Sun, 22 Jun 2025 08:50:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607420; x=1751212220; 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=ow9ujsHQEkD1S1vI52/xmEQqYlvBstlixFiJehZIezQ=; b=WJV0fRY6avYFJEYqUdzbPpOUcdXB6RehMRFNtGREER9oAyerlbMJ3PQdo8ptVsVsEH v0iJNRIDUHu0bv5LoYVd+0SNEC6z/vTWTeVR0R7EWVOM+Ic71pe3hdA7c6c+6zXBWMfV 0hILhLm/dvLyOb3VbHMAr0IfCj+k5b9+2MyZyKvDu5HTStjrU+MTITrGjoF66u2+2LmB JhtTfFCZY4EgtcA6oPkVHm+6X+cQMMSkn1Ik8QZrb15G7MI3M2U2oRUG+s+iUMraY2Jz 7UoWZyjtzVWutjTZ0InX5oLuMAZU+TPh7Ml/Xrl+Tj9ZtbKmapfsiJnl047Ms4+4vG2w V/9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607420; x=1751212220; 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=ow9ujsHQEkD1S1vI52/xmEQqYlvBstlixFiJehZIezQ=; b=Bw8GtjG7BRC0PWqgSj4vlt+GZ5l6EWycP6cAYleH24NVPgK2rEEL7CSaBOOdR/z5Nl w4f4Jrgmuu59jvkbfqSp84QLjpm+MxyJG8QgpzdRTbqCMnTlABJP9y/bnhmDBEUx2TqX X2R2dhUx/+mSLYsC5M5+wY206dh/ozSITcFOaUk/WEyA0XbHlBMBj+6YoDDHqt1KcZAB 4MhTkvSUqJgRhxnNg8jC6Vc+VWZd8Lgwn+0uROODx0XqzHW1spVDwiSPlDFamWkmBS5x FJlgq35QVFnvBLC6ZPEOp9+75ofDS7hPE3k1oFgOE/BVhnBL+S2KZlTG4XaH9VF9/QTB SDKQ== X-Forwarded-Encrypted: i=1; AJvYcCXcWIvMAI8iUKLhriAqZCY3nBOVH7fnGg4FAiXVC7ktaIdMyQFNxAPnCXVfiKKWbzNdLOnUnIcjF4tRAbX6@vger.kernel.org, AJvYcCXgArKIDXznW11AsXyr61yj/3UI8rxnH4HP95qPkV8zczbN2VxT/l9Ku8bVSOBkan+jI1ULi3WSOow=@vger.kernel.org X-Gm-Message-State: AOJu0YwQXW+7uCZoJJCa4HwHaHFAcIgPMe0AaDvBaiokOezuZ4azkC2z sazsgxJxbYddWc9iSSPYY49AcFIMtsb4Kr71lH4H79nk5xx6wqJTJqe+fIZeVw== X-Gm-Gg: ASbGncsRDPdXG7cSaJoUoHgHA4R1oKFneF57hJ7ZGroj4ESQTTw866mAjYwFcXwrfCG ThUwcEK9gbywce8Dd7HoNz8iW9Lj7GT1ozbLIx3EQd/7/qx1NkQnQFFaVT/mm/7oax6i+Nntpwm ja3lqaNJV1g67cvowrgpXCK68K87c2vkvrxYs2pLoqxd4nXoAeUjeQ3BJVVg07jDarlyoqEKgub PrFyA9yR1e26p1JZinQMf4oiwEJtYK+7f/gs/G/kMIgUPKnhJfT9tmW8UBDzKBQob5SxcS5bonn rVTZi5r4MZDH9fG1hFmhlS+fjQhlQWdshW//wIRrol/ItOCWrWugwUS3/03Jfi4krO0YX4t73Mm A1HH2uCPVlsmM1G4e656xHONejE4W1RQ6jC3SUExemes= X-Google-Smtp-Source: AGHT+IFD8wcr6ihxIXvxSxY44HMvEsRDM0Bkg5z4dbjCoXtn+v6Ucl+U8fuW9uihhbwIjRB+3gkn9A== X-Received: by 2002:a17:907:94c3:b0:ade:8a6:b86b with SMTP id a640c23a62f3a-ae057c3b2b3mr279707566b.16.1750607419661; Sun, 22 Jun 2025 08:50:19 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:19 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 5/7] iio: accel: adxl345: add coupling detection for activity/inactivity Date: Sun, 22 Jun 2025 15:50:08 +0000 Message-Id: <20250622155010.164451-6-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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" Enable AC/DC coupling configuration for activity and inactivity detection by setting the AC/DC bit. Extend existing magnitude-based detection with adaptive AC-coupled mode. Use DC-coupled mode to compare acceleration samples directly against configured thresholds. Use AC-coupled mode to compare samples against a reference taken at the start of activity detection. Implement DC-coupled events using MAG, and AC-coupled events using MAG_ADAPTIVE. Expose configuration of thresholds and periods via separate sysfs handles. Note that both coupling modes share the same sensor registers, so activity or inactivity detection cannot be configured for both AC and DC simultaneously. Apply the most recently configured mode. Simplify event handling and support adaptive AC-coupling. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 253 +++++++++++++++++++++++++++++-- 1 file changed, 238 insertions(+), 15 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index 3faf1af013c7..c5a3dac5f938 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -38,6 +38,8 @@ #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_REG_ACT_ACDC_MSK BIT(7) +#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_COUPLING_DC 0 +#define ADXL345_COUPLING_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 { @@ -186,6 +204,13 @@ static struct iio_event_spec adxl345_events[] =3D { .mask_shared_by_type =3D BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), }, + { + /* activity, ac bit set */ + .type =3D IIO_EV_TYPE_MAG_ADAPTIVE, + .dir =3D IIO_EV_DIR_RISING, + .mask_shared_by_type =3D BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE), + }, { /* single tap */ .type =3D IIO_EV_TYPE_GESTURE, @@ -239,6 +264,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_ADAPTIVE, + .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 { @@ -346,12 +379,114 @@ static int adxl345_set_inact_time(struct adxl345_sta= te *st, u32 val_s) return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); } =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. + * + * 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: true if configured coupling matches the provided type, else a n= egative + * error value. + */ +static int adxl345_is_act_inact_ac(struct adxl345_state *st, + enum adxl345_activity_type type) +{ + unsigned int regval; + bool coupling; + int ret; + + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + coupling =3D adxl345_act_acdc_msk[type] & regval; + + switch (type) { + case ADXL345_ACTIVITY: + case ADXL345_INACTIVITY: + return coupling =3D=3D ADXL345_COUPLING_DC; + case ADXL345_ACTIVITY_AC: + case ADXL345_INACTIVITY_AC: + return coupling =3D=3D ADXL345_COUPLING_AC; + default: + return -EINVAL; + } +} + +/** + * adxl345_set_act_inact_ac() - Configure AC coupling or DC coupling. + * + * @st: The device data. + * @type: Provide a type of activity or inactivity. + * @cmd_en: enable or disable AC coupling. + * + * 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, + bool cmd_en) +{ + unsigned int act_inact_ac; + + if (type =3D=3D ADXL345_ACTIVITY_AC || type =3D=3D ADXL345_INACTIVITY_AC) + act_inact_ac =3D ADXL345_COUPLING_AC && cmd_en; + else + act_inact_ac =3D ADXL345_COUPLING_DC && cmd_en; + + /* + * 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_assign_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 adxl345_activity_type type) { unsigned int axis_ctrl; unsigned int regval; - bool en; + bool int_en, en; int ret; =20 ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl); @@ -361,6 +496,7 @@ static int adxl345_is_act_inact_en(struct adxl345_state= *st, /* Check if axis for activity are enabled */ switch (type) { case ADXL345_ACTIVITY: + case ADXL345_ACTIVITY_AC: en =3D FIELD_GET(ADXL345_ACT_X_EN, axis_ctrl) | FIELD_GET(ADXL345_ACT_Y_EN, axis_ctrl) | FIELD_GET(ADXL345_ACT_Z_EN, axis_ctrl); @@ -368,6 +504,7 @@ static int adxl345_is_act_inact_en(struct adxl345_state= *st, return false; break; case ADXL345_INACTIVITY: + case ADXL345_INACTIVITY_AC: en =3D FIELD_GET(ADXL345_INACT_X_EN, axis_ctrl) | FIELD_GET(ADXL345_INACT_Y_EN, axis_ctrl) | FIELD_GET(ADXL345_INACT_Z_EN, axis_ctrl); @@ -383,23 +520,39 @@ static int adxl345_is_act_inact_en(struct adxl345_sta= te *st, if (ret) return ret; =20 - return adxl345_act_int_reg[type] & regval; + int_en =3D adxl345_act_int_reg[type] & regval; + if (!int_en) + return false; + + /* Check if configured coupling matches provided type */ + return adxl345_is_act_inact_ac(st, type); } =20 static int adxl345_set_act_inact_linkbit(struct adxl345_state *st, enum adxl345_activity_type type, bool en) { - int act_en, inact_en; + int act_en, act_ac_en, inact_en, inact_ac_en; =20 act_en =3D adxl345_is_act_inact_en(st, ADXL345_ACTIVITY); if (act_en < 0) return act_en; =20 + act_ac_en =3D adxl345_is_act_inact_en(st, ADXL345_ACTIVITY_AC); + if (act_ac_en < 0) + return act_ac_en; + inact_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); if (inact_en < 0) return inact_en; =20 + inact_ac_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC); + if (inact_ac_en < 0) + return inact_ac_en; + + inact_en =3D inact_en || inact_ac_en; + act_en =3D act_en || act_ac_en; + return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_INACT_MSK, en && act_en && inact_en); @@ -426,7 +579,7 @@ static int adxl345_set_act_inact_en(struct adxl345_stat= e *st, return 0; =20 /* When turning on inactivity, check if inact time is valid */ - if (type =3D=3D ADXL345_INACTIVITY) { + if (type =3D=3D ADXL345_INACTIVITY || type =3D=3D ADXL345_INACTIVITY_AC)= { ret =3D regmap_read(st->regmap, ADXL345_REG_TIME_INACT, &period); @@ -436,6 +589,16 @@ static int adxl345_set_act_inact_en(struct adxl345_sta= te *st, if (!period) return 0; } + } else { + /* + * When turning off an activity, ensure that the correct + * coupling event is specified. This step helps prevent misuse - + * for example, if an AC-coupled activity is active and the + * current call attempts to turn off a DC-coupled activity, this + * inconsistency should be detected here. + */ + if (adxl345_is_act_inact_ac(st, type) <=3D 0) + return 0; } =20 /* Start modifying configuration registers */ @@ -446,10 +609,12 @@ static int adxl345_set_act_inact_en(struct adxl345_st= ate *st, /* Enable axis according to the command */ switch (type) { case ADXL345_ACTIVITY: + case ADXL345_ACTIVITY_AC: axis_ctrl =3D ADXL345_ACT_X_EN | ADXL345_ACT_Y_EN | ADXL345_ACT_Z_EN; break; case ADXL345_INACTIVITY: + case ADXL345_INACTIVITY_AC: axis_ctrl =3D ADXL345_INACT_X_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_Z_EN; break; @@ -462,6 +627,11 @@ static int adxl345_set_act_inact_en(struct adxl345_sta= te *st, if (ret) return ret; =20 + /* Update AC/DC-coupling according to the command */ + ret =3D adxl345_set_act_inact_ac(st, type, cmd_en); + if (ret) + return ret; + /* Enable the interrupt line, according to the command */ ret =3D regmap_assign_bits(st->regmap, ADXL345_REG_INT_ENABLE, adxl345_act_int_reg[type], cmd_en); @@ -955,6 +1125,10 @@ static int adxl345_read_event_config(struct iio_dev *= indio_dev, return adxl345_read_mag_config(st, dir, ADXL345_ACTIVITY, ADXL345_INACTIVITY); + case IIO_EV_TYPE_MAG_ADAPTIVE: + return adxl345_read_mag_config(st, dir, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -991,6 +1165,11 @@ static int adxl345_write_event_config(struct iio_dev = *indio_dev, ADXL345_ACTIVITY, ADXL345_INACTIVITY, state); + case IIO_EV_TYPE_MAG_ADAPTIVE: + return adxl345_write_mag_config(st, dir, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, + state); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -1100,6 +1279,11 @@ static int adxl345_read_event_value(struct iio_dev *= indio_dev, ADXL345_ACTIVITY, ADXL345_INACTIVITY, val, val2); + case IIO_EV_TYPE_MAG_ADAPTIVE: + return adxl345_read_mag_value(st, dir, info, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, + val, val2); case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -1158,6 +1342,14 @@ static int adxl345_write_event_value(struct iio_dev = *indio_dev, if (ret) return ret; break; + case IIO_EV_TYPE_MAG_ADAPTIVE: + ret =3D adxl345_write_mag_value(st, dir, info, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, + val, val2); + if (ret) + return ret; + break; case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -1402,6 +1594,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 @@ -1426,22 +1619,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_ADAPTIVE, + 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_ADAPTIVE, + 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 Thu Oct 9 00:37:50 2025 Received: from mail-ed1-f53.google.com (mail-ed1-f53.google.com [209.85.208.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 A5FD11FFC7E; Sun, 22 Jun 2025 15:50:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607425; cv=none; b=o4udmQ5h+db6GQ0hmeWqw/0O8HPgOUoCe8WWeeMCuoekbY23WF7xaco7EDyjaLU0UzlqQyo0hQ+CBzaooexD4SJmt2Yim18vFC5wb8ft2tPMJz8lQ7I6S7THX4S8oQ1gPV4jDgbJuUa+WC2gXYrmFYzb4CMECnhNNWsRHsJvzh8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607425; c=relaxed/simple; bh=B+2nO65ApKKPy8e7Ga2hlszF64aBJTf+8dYktop5uVE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Gptq74AutXrEQoYTJZexPyEJMJa7K/M/O4TGgvNjncKScc6cJ4alF193mJjOt3AJch+wgcl1a2AaQV+m2iSCWbhReFW/i9KWmiVBmv8OtO6OxyTylwXYnP41tV0nnF5xc+KHSbomhlDPxPPZXDltKNDCZ7elMmlJPq34SuyJ7TI= 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=dC1mnQZ1; arc=none smtp.client-ip=209.85.208.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="dC1mnQZ1" Received: by mail-ed1-f53.google.com with SMTP id 4fb4d7f45d1cf-607780f0793so675797a12.2; Sun, 22 Jun 2025 08:50:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607421; x=1751212221; 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=SwdBygc9qVp9kulnWBDNSOpL5ulvrlGHjGtt+VSO4VQ=; b=dC1mnQZ1PS9VepGk/RhJlUiCalFvZ/Cftf6UnYR3vT73hDyy0/HDu7TM4N6HTFJxeA eXmlfVoh4Rmjr96xOisV1tgn3e4Uy5ylyTRpFLS4JRC2L9pmGbCcfol22j4VKeuS59kK vKf9qg3MMh8ELKn05F0hGzK+EzCa1DMEesqqA6MMuimzceiMdw4gyF32ohzuF3ZKRLJ8 a30YkM/i8ujUXwNzE+W21+Z7wRimRo0BxdYhGEZIs5hQPTrXbfxPjJ/P1AR0yw+hsjrs oZfkr+jMi/ohKGHMNfYz4pe07CujayfWfxv8N2pD1cT8bOQbRlgGmMl1KPayzabWSHgg d4RA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607421; x=1751212221; 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=SwdBygc9qVp9kulnWBDNSOpL5ulvrlGHjGtt+VSO4VQ=; b=nO9U7D1hXwglycmPdnf3nAI4Y4r93pT1fPt7geyCPLDWadrrj1rkCaPueRgXrm3+8J sXfAv8OWQyrC7CsJ78RjiXQPXsXiNAL42jzlYcs493QYRkiUet690HRz2EUsXLfsQuYB 2X1tJd6t0IpNChhgfjHFE152m46hmYN0gO7IWq3B08YZy2HoH9IOBMoIQRKqAjE4PHrs cN5znI6s1eSEJJsre/5qYBv+HmRhxtojhCtcLCwB1akQq9ADnewQcEt5h49zNBKKxBuU yRlIqHuOayiXjdrfVK02ppJ3/dzngk6AbEB0dP0lrhxHYPA9PO8PEkb76+x2yx15IP0H ftVg== X-Forwarded-Encrypted: i=1; AJvYcCVgobZiSNLG3AOX+MKxT+Dlf2AwfRb0dO/D7aktEJ0itfIJmKBXl3rwym0IbCvVMvFXnNYTRrhqpoMQ0/87@vger.kernel.org, AJvYcCXEt452b9fHYebDO42Ep29Ihc5dxsofoWsX+qPMR5Iv6GJ29w7dcn4fsAQTWhrPSLMgHlp7zOlTowY=@vger.kernel.org X-Gm-Message-State: AOJu0YyLOmeuQOfCZZ7PDsyDTZrCZaE2lcH9vcekaw6rfnYDvln310yn ii0nOPkg9LqcqZvvabHF4WwQhENCCZ7FWL+3qys/Y7OwiLFzej1GJXnafHdnBQ== X-Gm-Gg: ASbGncvDvvkvsc+nHTxGTavjgqqO+djxcizr9EkPgx2qflSQ1QAqGdm2wa7xeQihcso VohiTu6OaRrs7pqJXr6eBBf5ErzK38mNwpYlmdGolHMp9/+jbcI2Vr5JOYSYvoazSzxWWdrq2L8 CLFZYtir0hff0VMTK9MEh+nUYwcAD7y/8htNLoPnr+kkfXbHK4PCYkvA8yMKXpC86xrPwhdldLA tQL1UQ8zsJEPKJkZRWtE+eCVEhyoPlvzRYAByLUot+2lR8vlBszd9zulFZQ8jwVHpLzISg084ZQ XyNS5S8RfrF4Fb+evyiIAxQx6PCfsBb9MRnSr72elWr7T/XaVpUI92g44AI5Cjvj/mAO78uUNl5 mxSJDPk157oDgqDPmRYdgIdPophMqGVhf X-Google-Smtp-Source: AGHT+IFgBbJg1VpU8mtqvVV7aE3oAEuJwY3NpmDGYDIyx4r6eC+OHOoi7OJWGH8i1ifpxr7RUcUXcQ== X-Received: by 2002:a17:906:dc8d:b0:ad8:9372:870a with SMTP id a640c23a62f3a-ae0578e80f1mr294711566b.3.1750607420716; Sun, 22 Jun 2025 08:50:20 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:20 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 6/7] iio: accel: adxl345: extend inactivity time for less than 1s Date: Sun, 22 Jun 2025 15:50:09 +0000 Message-Id: <20250622155010.164451-7-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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" Inactivity and free-fall events are essentially the same type of sensor events. Therefore, inactivity detection (normally set for periods between 1 and 255 seconds) can be extended for shorter durations to support free-fall detection. For periods shorter than 1 second, the driver automatically configures the threshold and duration using the free-fall register. For periods longer than 1 second, it uses the inactivity threshold and duration using the inactivity registers. When using the free-fall register, the link bit is not set, which means auto-sleep cannot be enabled if activity detection is also active. Signed-off-by: Lothar Rubusch --- drivers/iio/accel/adxl345_core.c | 158 +++++++++++++++++++++---------- 1 file changed, 109 insertions(+), 49 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_c= ore.c index c5a3dac5f938..f1f92635bc21 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -40,12 +40,15 @@ #define ADXL345_REG_INACT_AXIS_MSK GENMASK(2, 0) #define ADXL345_REG_ACT_ACDC_MSK BIT(7) #define ADXL345_REG_INACT_ACDC_MSK BIT(3) +#define ADXL345_REG_NO_ACDC_MSK 0x00 #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_ACT_INACT_NO_AXIS_EN 0x00 + #define ADXL345_INACT_Z_EN BIT(0) #define ADXL345_INACT_Y_EN BIT(1) #define ADXL345_INACT_X_EN BIT(2) @@ -86,6 +89,7 @@ enum adxl345_activity_type { ADXL345_INACTIVITY, ADXL345_ACTIVITY_AC, ADXL345_INACTIVITY_AC, + ADXL345_INACTIVITY_FF, }; =20 static const unsigned int adxl345_act_int_reg[] =3D { @@ -93,6 +97,7 @@ static const unsigned int adxl345_act_int_reg[] =3D { [ADXL345_INACTIVITY] =3D ADXL345_INT_INACTIVITY, [ADXL345_ACTIVITY_AC] =3D ADXL345_INT_ACTIVITY, [ADXL345_INACTIVITY_AC] =3D ADXL345_INT_INACTIVITY, + [ADXL345_INACTIVITY_FF] =3D ADXL345_INT_FREE_FALL, }; =20 static const unsigned int adxl345_act_thresh_reg[] =3D { @@ -100,6 +105,7 @@ static const unsigned int adxl345_act_thresh_reg[] =3D { [ADXL345_INACTIVITY] =3D ADXL345_REG_THRESH_INACT, [ADXL345_ACTIVITY_AC] =3D ADXL345_REG_THRESH_ACT, [ADXL345_INACTIVITY_AC] =3D ADXL345_REG_THRESH_INACT, + [ADXL345_INACTIVITY_FF] =3D ADXL345_REG_THRESH_FF, }; =20 static const unsigned int adxl345_act_acdc_msk[] =3D { @@ -107,6 +113,7 @@ static const unsigned int adxl345_act_acdc_msk[] =3D { [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, + [ADXL345_INACTIVITY_FF] =3D ADXL345_REG_NO_ACDC_MSK, }; =20 enum adxl345_odr { @@ -189,6 +196,9 @@ struct adxl345_state { u8 watermark; u8 fifo_mode; =20 + u8 inact_threshold; + u32 inact_time_ms; + u32 tap_duration_us; u32 tap_latent_us; u32 tap_window_us; @@ -333,10 +343,29 @@ static int adxl345_set_measure_en(struct adxl345_stat= e *st, bool en) =20 /* activity / inactivity */ =20 +static int adxl345_set_inact_threshold(struct adxl345_state *st, + unsigned int threshold) +{ + int ret; + + st->inact_threshold =3D min(U8_MAX, threshold); + + ret =3D regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY], + st->inact_threshold); + if (ret) + return ret; + + return regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY_FF], + st->inact_threshold); +} + /** * adxl345_set_inact_time - Configure inactivity time explicitly or by ODR. * @st: The sensor state instance. - * @val_s: A desired time value, between 0 and 255. + * @val_int: The inactivity time, integer part. + * @val_fract: The inactivity time, fractional part when val_int is 0. * * Inactivity time can be configured between 1 and 255 seconds. If a user = sets * val_s to 0, a default inactivity time is calculated automatically (sinc= e 0 is @@ -357,16 +386,18 @@ static int adxl345_set_measure_en(struct adxl345_stat= e *st, bool en) * * Return: 0 or error value. */ -static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s) +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int, + u32 val_fract) { int max_boundary =3D U8_MAX; int min_boundary =3D 10; - unsigned int val =3D min(val_s, U8_MAX); + unsigned int val; enum adxl345_odr odr; unsigned int regval; int ret; =20 - if (val =3D=3D 0) { + if (val_int =3D=3D 0 && val_fract =3D=3D 0) { + /* Generated inactivity time based on ODR */ ret =3D regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); if (ret) return ret; @@ -374,9 +405,31 @@ static int adxl345_set_inact_time(struct adxl345_state= *st, u32 val_s) odr =3D FIELD_GET(ADXL345_BW_RATE_MSK, regval); val =3D clamp(max_boundary - adxl345_odr_tbl[odr][0], min_boundary, max_boundary); + st->inact_time_ms =3D MILLI * val; + + /* Inactivity time in s */ + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); + } else if (val_int =3D=3D 0 && val_fract > 0) { + /* time < 1s, free-fall */ + + /* + * Datasheet max. value is 255 * 5000 us =3D 1.275000 seconds. + * + * Recommended values between 100ms and 350ms (0x14 to 0x46) + */ + st->inact_time_ms =3D DIV_ROUND_UP(val_fract, MILLI); + + return regmap_write(st->regmap, ADXL345_REG_TIME_FF, + DIV_ROUND_CLOSEST(val_fract, 5)); + } else if (val_int > 0) { + /* Time >=3D 1s, inactivity */ + st->inact_time_ms =3D MILLI * val_int; + + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int); } =20 - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); + /* Do not support negative or wrong input. */ + return -EINVAL; } =20 /** @@ -399,6 +452,9 @@ static int adxl345_is_act_inact_ac(struct adxl345_state= *st, bool coupling; int ret; =20 + if (type =3D=3D ADXL345_INACTIVITY_FF) + return true; + ret =3D regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); if (ret) return ret; @@ -511,6 +567,9 @@ static int adxl345_is_act_inact_en(struct adxl345_state= *st, if (!en) return false; break; + case ADXL345_INACTIVITY_FF: + en =3D true; + break; default: return -EINVAL; } @@ -542,15 +601,20 @@ static int adxl345_set_act_inact_linkbit(struct adxl3= 45_state *st, if (act_ac_en < 0) return act_ac_en; =20 - inact_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); - if (inact_en < 0) - return inact_en; + if (type =3D=3D ADXL345_INACTIVITY_FF) { + inact_en =3D false; + } else { + inact_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); + if (inact_en < 0) + return inact_en; =20 - inact_ac_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC); - if (inact_ac_en < 0) - return inact_ac_en; + inact_ac_en =3D adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC); + if (inact_ac_en < 0) + return inact_ac_en; + + inact_en =3D inact_en || inact_ac_en; + } =20 - inact_en =3D inact_en || inact_ac_en; act_en =3D act_en || act_ac_en; =20 return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL, @@ -569,11 +633,15 @@ static int adxl345_set_act_inact_en(struct adxl345_st= ate *st, =20 if (cmd_en) { /* When turning on, check if threshold is valid */ - ret =3D regmap_read(st->regmap, - adxl345_act_thresh_reg[type], - &threshold); - if (ret) - return ret; + if (type =3D=3D ADXL345_ACTIVITY || type =3D=3D ADXL345_ACTIVITY_AC) { + ret =3D regmap_read(st->regmap, + adxl345_act_thresh_reg[type], + &threshold); + if (ret) + return ret; + } else { + threshold =3D st->inact_threshold; + } =20 if (!threshold) /* Just ignore the command if threshold is 0 */ return 0; @@ -618,6 +686,9 @@ static int adxl345_set_act_inact_en(struct adxl345_stat= e *st, axis_ctrl =3D ADXL345_INACT_X_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_Z_EN; break; + case ADXL345_INACTIVITY_FF: + axis_ctrl =3D ADXL345_ACT_INACT_NO_AXIS_EN; + break; default: return -EINVAL; } @@ -884,7 +955,7 @@ static int adxl345_set_odr(struct adxl345_state *st, en= um adxl345_odr odr) return ret; =20 /* update inactivity time by ODR */ - return adxl345_set_inact_time(st, 0); + return adxl345_set_inact_time(st, 0, 0); } =20 static int adxl345_find_range(struct adxl345_state *st, int val, int val2, @@ -921,12 +992,6 @@ static int adxl345_set_range(struct adxl345_state *st,= enum adxl345_range range) if (ret) return ret; =20 - 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)); @@ -937,6 +1002,7 @@ static int adxl345_set_range(struct adxl345_state *st,= enum adxl345_range range) / adxl345_range_factor_tbl[range]; act_threshold =3D min(U8_MAX, max(1, act_threshold)); =20 + inact_threshold =3D st->inact_threshold; inact_threshold =3D inact_threshold * adxl345_range_factor_tbl[range_old] / adxl345_range_factor_tbl[range]; inact_threshold =3D min(U8_MAX, max(1, inact_threshold)); @@ -946,8 +1012,7 @@ static int adxl345_set_range(struct adxl345_state *st,= enum adxl345_range range) if (ret) return ret; =20 - return regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_INACTIVITY= ], - inact_threshold); + return adxl345_set_inact_threshold(st, inact_threshold); } =20 static int adxl345_read_avail(struct iio_dev *indio_dev, @@ -1192,7 +1257,6 @@ static int adxl345_read_mag_value(struct adxl345_stat= e *st, int *val, int *val2) { unsigned int threshold; - unsigned int period; int ret; =20 switch (info) { @@ -1208,25 +1272,16 @@ static int adxl345_read_mag_value(struct adxl345_st= ate *st, *val2 =3D MICRO; return IIO_VAL_FRACTIONAL; case IIO_EV_DIR_FALLING: - ret =3D regmap_read(st->regmap, - adxl345_act_thresh_reg[type_inact], - &threshold); - if (ret) - return ret; - *val =3D 62500 * threshold; + *val =3D 62500 * st->inact_threshold; *val2 =3D MICRO; return IIO_VAL_FRACTIONAL; default: return -EINVAL; } case IIO_EV_INFO_PERIOD: - ret =3D regmap_read(st->regmap, - ADXL345_REG_TIME_INACT, - &period); - if (ret) - return ret; - *val =3D period; - return IIO_VAL_INT; + *val =3D st->inact_time_ms; + *val2 =3D MILLI; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -1249,14 +1304,12 @@ static int adxl345_write_mag_value(struct adxl345_s= tate *st, adxl345_act_thresh_reg[type_act], val); case IIO_EV_DIR_FALLING: - return regmap_write(st->regmap, - adxl345_act_thresh_reg[type_inact], - val); + return adxl345_set_inact_threshold(st, val); default: return -EINVAL; } case IIO_EV_INFO_PERIOD: - return adxl345_set_inact_time(st, val); + return adxl345_set_inact_time(st, val, val2); default: return -EINVAL; } @@ -1669,6 +1722,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) @@ -1907,15 +1971,11 @@ 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, 0x37); - 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); + ret =3D adxl345_set_inact_threshold(st, 4); if (ret) return ret; =20 --=20 2.39.5 From nobody Thu Oct 9 00:37:50 2025 Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.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 BD4C4201000; Sun, 22 Jun 2025 15:50:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607426; cv=none; b=jtDUEZBnzQjeRZoCqo+T6R3h5g/i7WTSxlnpaklnWO5frXmaMa6Lu9IkinezStI/j17AzSLJpfbVWBWzCsDBWwJD/yGnNdSCxIBQ/WE/llq297g9SDiwayDcoNjIps7LU59M3NF/M6JZvD6p8oVlHHd5OCchKrNg/EJtDJhVYOc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750607426; c=relaxed/simple; bh=L0i1qY41Z5lFOGjmot818iJl0CIgBGpA94zMKQ2Ieo0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=k0dNcdXpLCwagntzJeI+hR5zj5A3SNkkniNmvm9geWjecIK0DqexWZNvuQVvDSelBG7Yp/T9bVKpmIOo0+qQ4Dslv72Lu6bcMxEvIWv2kgPSTh5WVrR3dMzltEWMiepmujRzkoLKZWzlJjjqFYUgz0/b7NzrfxTAVVB1QmYT5mg= 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=LZWKHnTQ; arc=none smtp.client-ip=209.85.208.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="LZWKHnTQ" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-6071ac68636so730432a12.3; Sun, 22 Jun 2025 08:50:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750607422; x=1751212222; 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=pFbA4nZrhIjOTRXo2cWFm3BgeSdAuZKyGSQo86/VIng=; b=LZWKHnTQSPtvO7UVxNGyw48ATrEx0a6RJp7H/5Lb754EDUqfQetZIj9pM+9vNDkJYs 6VpkhSigMvq/0rQDs5RncF7Vgnn8f+rdAGlnOR4O41ODYXo1LkqM91dBSlX5hjpWf+sX 4DdEND2ee5W1p/vBftjsy66DhxYbyfHGJPHZeNwsILtm1iRznRjzI1aczLTYqbda1fUu cPFYD3zcagFLvZM/0Vmz0gBDoZtV+m2init3dvNbVsvq3fTzKRYiEEoOl6dC5hmhqKyq Tbxo/npTFw6F7T6MqV+8CwQwsmGMruBeX4ny7jQ6/62/Su4x8AYo92Fqp7jCHdfPfbMA tYhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750607422; x=1751212222; 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=pFbA4nZrhIjOTRXo2cWFm3BgeSdAuZKyGSQo86/VIng=; b=ZsgAok4ndvF4uCNUN8+fD8/djbbgQiRH6CwHUownwpTbcNFFmcuhRKB1PN18U7j7Z5 TDYjfOAl7FYaVTZtITcuNIFUjLQs74E+ALxjKWjyj8VYdyzPfinQwp2YoJ3aX6PqUUlK zvvcd2UW7gQ1Q/47H9O7PRa5om5OpSJt/ijs1oaOPb5L3wo4+utvhc9kQwR0PGXhg9+i pN2ggzu7qGBn2nkcbeGi/E5A1yygsx7PwRQfW+igt9DxqFTyDQDium8/RBu8WJhHCK35 na8kfmJCbbYfBe8L6JcfcaWasC76wJWKuE9CFKa7HD5w15hZ7veSwybNlG3IVv/OFcJ6 OrPw== X-Forwarded-Encrypted: i=1; AJvYcCUqqOoFO207RxN9gsIWYeqjsToVf7TbI6T4WxBtPWOzQ2cC8CCWDKRYyE3YusGMhpKYsq1fVnvHizM=@vger.kernel.org, AJvYcCWws9QQc/1RrvNL1X8AvldL10g59lwctpapNAWVmeyloCmG8W2XIBOSp9F0F2y0LoLJeKqdWQ/M6IPXRXbi@vger.kernel.org X-Gm-Message-State: AOJu0Yz51DxZjzEpH7cDyOkOFSosutCFmfFnZLPvPi+a6L/OPWLbIf3e HAh+h3L+7gP4VhZkHwH9qHBH4uf1GrMwbUUIao/qeKQoljrovgl+iD03 X-Gm-Gg: ASbGncuLpI2GIf/zAJNr0uFJiOdSbKod1DfuGpl1vZVkeARKwIOEGxamgprlDxO0O0q 1sv+b/n9WQ3zAOG35RXxai3UXwYNNclkPE2+Co4gFm0bkr4EDWRE74CSnYQIDEjmV+fZzysA841 fCtuALjWsovjAN6AnAD7rTGmSC6T+H8uh6nEug/LaeOsf+5Ef73hydOMU+TOVTnrQcQFZsxqFvs Bp5PQKVoY9QPWsA8gyxw2OZjuMl0kxkwHWJlnY/jtI6p1qImTXhakUMXZLDxnYfvVSnLLIx0Th3 dZaAyNhTLUO5mA34z6stNqztk1BmkxRyCb9gI7K+ucKl2yj57Jlmt0jE8pX3ug4HCgFTqB7JmDY 0p7mEbOIfgn/rdzQmXTwneMC6wjyoWLX6 X-Google-Smtp-Source: AGHT+IE2OJEy9k8zipk3u+wGBjOqMS3jnIP3IdhK9pcG/1Hy8h2gaTthzrK+P7y2VRP8GLKGZJAIoQ== X-Received: by 2002:a17:907:97ca:b0:ad8:87d1:fec4 with SMTP id a640c23a62f3a-ae057927a02mr324379166b.7.1750607421825; Sun, 22 Jun 2025 08:50:21 -0700 (PDT) Received: from localhost.localdomain (84-72-156-211.dclient.hispeed.ch. [84.72.156.211]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae053ecbd9esm552781966b.38.2025.06.22.08.50.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Jun 2025 08:50:21 -0700 (PDT) From: Lothar Rubusch To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com, andy@kernel.org, corbet@lwn.net Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, eraretuya@gmail.com, l.rubusch@gmail.com Subject: [PATCH v10 7/7] docs: iio: add documentation for adxl345 driver Date: Sun, 22 Jun 2025 15:50:10 +0000 Message-Id: <20250622155010.164451-8-l.rubusch@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250622155010.164451-1-l.rubusch@gmail.com> References: <20250622155010.164451-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 | 443 ++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 444 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..c5525267ea12 --- /dev/null +++ b/Documentation/iio/adxl345.rst @@ -0,0 +1,443 @@ +.. 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 +------------- + +Specific IIO events are triggered by their corresponding interrupts. The s= ensor +driver supports either none or a single active interrupt (INT) line, selec= table +from the two available options: INT1 or INT2. The active INT line should be +specified in the device tree. If no INT line is configured, the sensor def= aults +to FIFO bypass mode, where event detection is disabled and only X, Y, and = Z axis +measurements are available. + +The table below lists the ADXL345-related device files located in the +device-specific path: ``/sys/bus/iio/devices/iio:deviceX/events``. +Note that activity and inactivity detection are DC-coupled by default; +therefore, only the AC-coupled activity and inactivity events are explicit= ly +listed. + ++---------------------------------------------+---------------------------= ------------------+ +| 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_adaptive_rising_en | Enable AC coupled activity= on X axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_adaptive_falling_period | AC coupled inactivity time= in seconds | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_adaptive_falling_value | AC coupled inactivity thre= shold in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_adaptive_rising_value | AC coupled activity thresh= old in 62.5/LSB | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_mag_rising_en | Enable activity detection = on X axis | ++---------------------------------------------+---------------------------= ------------------+ +| 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&y&z_mag_falling_en | Enable inactivity detectio= n on all axis | ++---------------------------------------------+---------------------------= ------------------+ +| in_accel_x&y&z_mag_adaptive_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_z_gesture_singletap_en | Enable single tap detectio= n on Z axis | ++---------------------------------------------+---------------------------= ------------------+ + +Please refer to the sensor's datasheet for a detailed description of this +functionality. + +Manually setting the **ODR** will cause the driver to estimate default val= ues +for inactivity detection timing, where higher ODR values correspond to lon= ger +default wait times, and lower ODR values to shorter ones. If these default= s do +not meet your application=E2=80=99s needs, you can explicitly configure th= e inactivity +wait time. Setting this value to 0 will revert to the default behavior. + +When changing the **g range** configuration, the driver attempts to estima= te +appropriate activity and inactivity thresholds by scaling the default valu= es +based on the ratio of the previous range to the new one. The resulting thr= eshold +will never be zero and will always fall between 1 and 255, corresponding t= o up +to 62.5=E2=80=AFg/LSB as specified in the datasheet. However, you can over= ride these +estimated thresholds by setting explicit values. + +When **activity** and **inactivity** events are enabled, the driver +automatically manages hysteresis behavior by setting the **link** and +**auto-sleep** bits. The link bit connects the activity and inactivity +functions, so that one follows the other. The auto-sleep function puts the +sensor into sleep mode when inactivity is detected, reducing power consump= tion +to the sub-12.5=E2=80=AFHz rate. + +The inactivity time is configurable between 1 and 255 seconds. In addition= to +inactivity detection, the sensor also supports free-fall detection, which,= from +the IIO perspective, is treated as a fall in magnitude across all axes. In +sensor terms, free-fall is defined using an inactivity period ranging from= 0.000 +to 1.000 seconds. + +The driver behaves as follows: +* If the configured inactivity period is 1 second or more, the driver uses= the + sensor's inactivity register. This allows the event to be linked with + activity detection, use auto-sleep, and be either AC- or DC-coupled. + +* If the inactivity period is less than 1 second, the event is treated as = plain + inactivity or free-fall detection. In this case, auto-sleep and coupling + (AC/DC) are not applied. + +* If an inactivity time of 0 seconds is configured, the driver selects a + heuristically determined default period (greater than 1 second) to optim= ize + power consumption. This also uses the inactivity register. + +Note: It is recommended to use the activity, inactivity, or free-fall regi= sters +when operating with an ODR between 12.5=E2=80=AFHz and 400=E2=80=AFHz. Acc= ording to the +datasheet, the recommended free-fall threshold is between 300=E2=80=AFmg a= nd 600=E2=80=AFmg +(register values 0x05 to 0x09), and the suggested free-fall time ranges fr= om +100=E2=80=AFms to 350=E2=80=AFms (register values 0x14 to 0x46). + +In DC-coupled mode, the current acceleration magnitude is directly compare= d to +the values in the THRESH_ACT and THRESH_INACT registers to determine activ= ity or +inactivity. In contrast, AC-coupled activity detection uses the accelerati= on +value at the start of detection as a reference point, and subsequent sampl= es are +compared against this reference. While DC-coupling is the default mode-com= paring +live values to fixed thresholds-AC-coupling relies on an internal filter +relative to the configured threshold. + +AC and DC coupling modes are configured separately for activity and inacti= vity +detection, but only one mode can be active at a time for each. For example= , if +AC-coupled activity detection is enabled and then DC-coupled mode is set, = only +DC-coupled activity detection will be active. In other words, only the most +recent configuration is applied. + +**Single tap** detection can be configured per the datasheet by setting the +threshold and duration parameters. When only single tap detection is enabl= ed, +the single tap interrupt triggers as soon as the acceleration exceeds the +threshold (marking the start of the duration) and then falls below it, pro= vided +the duration limit is not exceeded. If both single tap and double tap dete= ctions +are enabled, the single tap interrupt is triggered only after the double t= ap +event has been either confirmed or dismissed. + +To configure **double tap** detection, you must also set the window and la= tency +parameters in microseconds (=C2=B5s). The latency period begins once the s= ingle tap +signal drops below the threshold and acts as a waiting time during which a= ny +spikes are ignored for double tap detection. After the latency period ends= , the +detection window starts. If the acceleration rises above the threshold and= then +falls below it again within this window, a double tap event is triggered u= pon +the fall below the threshold. + +Double tap event detection is thoroughly explained in the datasheet. After= a +single tap event is detected, a double tap event may follow, provided the = signal +meets certain criteria. However, double tap detection can be invalidated f= or +three reasons: + +* If the **suppress bit** is set, any acceleration spike above the tap + threshold during the tap latency period immediately invalidates the doub= le tap + detection. In other words, no spikes are allowed during latency when the + suppress bit is active. + +* The double tap event is invalid if the acceleration is above the thresho= ld at + the start of the double tap window. + +* Double tap detection is also invalidated if the acceleration duration ex= ceeds + the limit set by the duration register. + +For double tap detection, the same duration applies as for single tap: the +acceleration must rise above the threshold and then fall below it within t= he +specified duration. Note that the suppress bit is typically enabled when d= ouble +tap detection is active. + +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 formula: + +.. 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_adaptive_rising_value + + ## AC coupled inactivity, threshold, [62.5/LSB] + root:/sys/bus/iio/devices/iio:device0> echo 4 > ./events/in_accel_= mag_adaptive_falling_value + + ## AC coupled inactivity, time [s] + root:/sys/bus/iio/devices/iio:device0> echo 3 > ./events/in_accel_= mag_adaptive_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 + + ## AC coupled activity, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= mag_adaptive_rising_en + + ## AC coupled inactivity, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_= x\&y\&z_mag_adaptive_falling_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. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 2d6afc5a8ed5..c333720c1c9f 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -32,6 +32,7 @@ Industrial I/O Kernel Drivers adis16480 adis16550 adxl380 + adxl345 bno055 ep93xx_adc opt4060 --=20 2.39.5