From nobody Sun Feb 8 07:07:47 2026 Received: from mail-ej1-f49.google.com (mail-ej1-f49.google.com [209.85.218.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D9882265CDD for ; Fri, 9 Jan 2026 18:15:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767982536; cv=none; b=YH1rMY4jCV2wUehNOVXBuJhqzSwV5c4rBG7OBC7Om6HeCMohkF5X57WJMJ1yxkDcd1o8AlchP+C59D60aPVSXiRF5jBpuIO5AUXC6tnSIVk7eJuhs2uBpNY4rnWlynuZqWg1gDhQW267fnjB2lEaJKHe1scSnOYpc+hheFeUMLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767982536; c=relaxed/simple; bh=ZOpc2KxPddw64+kCadhtkkyNHc9dGQ0OsK/5OVq5egE=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Xqri2VBu5aqAL7/CAWPzmggNzWC2hy9uzn4HytatskUgmeqoZ7l9VvFnneaM+SltflHJiBd4+SzlW/w/4imoYUUhUxPVJ48Dq3aVVNfH4YIQt90oBr/edq1Totdyp/XrEbSPYb0YB30C50rc+DTCF6lcA3hbjk7r2FLjos7twAA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=YlDd+nid; arc=none smtp.client-ip=209.85.218.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="YlDd+nid" Received: by mail-ej1-f49.google.com with SMTP id a640c23a62f3a-b7cee045187so585638566b.0 for ; Fri, 09 Jan 2026 10:15:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1767982533; x=1768587333; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=Dgqks7R0FZoV1F9cFxU5UZd69cs2yR4MsrhCcO8GYIA=; b=YlDd+nidQaVMvQBD2437+dMWJ0cz3PrHiHUMjlbLcrzdFOY7cr8Lp1syblXrgZg0pa g51NgU6RuHiL/Be7X0coVi0on+EYbZTnAsQwdny56Er1Ps2OeY0QHXuQ8P0FcnHJTGFD fitKCV6SxXLBg5q9CLGxpEr1lYpq9uoUJlsDdOz4kNkibV7+wmC7Xe+yOPgJ1Bebx/LK zDOgIuJC1TOvsO5akO9DT+zoCVaKLzQ0khBBgedgYrg+Cf9t6rcqo9sYEh1wdh9zHQUe jg06JFCuZ80M8l+sf2TwZSrW4dX7E5z9Oo+/04lQ/5hbxqtpkZaESulM1bhLYCm+vmh+ z/ZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982533; x=1768587333; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=Dgqks7R0FZoV1F9cFxU5UZd69cs2yR4MsrhCcO8GYIA=; b=OSlTpqpizjz5RCBB+thdlxoVhichkAABcxRW9XJlFHGZm1dcILxAzHrNFvwdEqwhQo MWrJtVQUjmpNTOmxVrgsH/Jcl90JtJodPq4i6kBudXBOM8qvB1fkmFZY0Z8/7vWqcUtO IxlzMdv9y2jfoigI96XsHsuRYuiwL8hu8KXrgm1LneLy3CSiqRCRtLUeNSp3r2UkdQlu QCqADSjxdapqqW9jb5NrxTE1lcpy94JVQH25kp96kjzP1KpBdfp1YYjkw9c+TCNckeTG axxuzQvkQYrAn9vN+5gGQSUNhdD6rRom5oj6cZ8oneF3KDzPYmb37011Y5l1lxxyK1vd 5GFA== X-Forwarded-Encrypted: i=1; AJvYcCXROPkxw5qA6gIDRBcdXU2AlEk50v/x0pxZvqXpoPM/8sOOPG7nNIHRtYTS6LpsKWFPO+QVN3jWWvhqac4=@vger.kernel.org X-Gm-Message-State: AOJu0YzO9MJkTHYTYACJDlbxAp9elDT0E2ht6GWNW7Wz8GYIN9RVcsn7 Y8uBa2duAwUTOPGHDwHzMPiqcZUsZtaz8/AThyK4ufuknugrtpkkx/Lp94XOoNO+YGA= X-Gm-Gg: AY/fxX4p8QNJcPhlN5TTmUlblB43ebhot4gqen68K8yrgTvWUAxG8jJT2C4X66AWS2w 1gtOqd+VJ0yK+7IFRioJZwQB5UEp8wIvVAf4tpvvxiqb5QwMMvbypQNb5UrVh+5zGvfmGhL+c3K BF8QVsJWUO9VH3Kt6QQSO7AO2p01ngd4ddhgrKeD5Z4WeKpAh+T/ITGd9xmOqYXQVSh/SUZ1Ysb N5Xu9XqHH2TzqjELNg3MpH25rBklmgFg7gM1OumP1Hpot88swkcykS4Uv5E1R4rqgwFTHrMOsep PewwrgBV52T4hnnyj9XxSjCupKFd+vGUEvQiD/i2FzOxSW2bu92wq29oI+4rTUk8TMgbZbhEL2T P5zoRe3gJJ5Al4yoy+jUO0nn3LCNrczKtEz3GiUlxFzRSSWb+J2f/+yfHLQ== X-Google-Smtp-Source: AGHT+IG8iWFuPY6KLX+yOq4PV+q/Os8YwVRbQEYUk+bVpfnwkkYWYheVzu2fIpEJUBt4tlw9GD1ejQ== X-Received: by 2002:a17:907:7801:b0:b73:1b97:5ddd with SMTP id a640c23a62f3a-b84298aaaf7mr1044870366b.8.1767982533126; Fri, 09 Jan 2026 10:15:33 -0800 (PST) Received: from localhost ([151.47.174.220]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b842a511829sm1169794966b.51.2026.01.09.10.15.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:15:32 -0800 (PST) From: Francesco Lavra To: Lorenzo Bianconi , Jonathan Cameron , David Lechner , =?UTF-8?q?Nuno=20S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/3] iio: imu: st_lsm6dsx: set buffer sampling frequency for accelerometer only Date: Fri, 9 Jan 2026 19:15:26 +0100 Message-Id: <20260109181528.154127-2-flavra@baylibre.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260109181528.154127-1-flavra@baylibre.com> References: <20260109181528.154127-1-flavra@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2112; i=flavra@baylibre.com; h=from:subject; bh=ZOpc2KxPddw64+kCadhtkkyNHc9dGQ0OsK/5OVq5egE=; b=owEB7QES/pANAwAKAe3xO3POlDZfAcsmYgBpYUWGnxlMsxmeQ4gVrt8dpFu7hV8AwHwnFxydf /B/JFZTOHOJAbMEAAEKAB0WIQSGV4VPlTvcox7DFObt8TtzzpQ2XwUCaWFFhgAKCRDt8TtzzpQ2 X5JkC/9rut/CdGQuqkN4BHgkmihEsa/eIQ84NQX359DJOuD45kbNBhwQOrwI3pgHvUQFEo2zNWm UkWhdukriXFFwq786FO0gedNQhpGsIrgp6OV3G+ZjJsyLjf+Z1kM+DUo+6383FaJQ5zqBESwgTy 2JxjWJSeSbs9qAUV0mTZGnp80rz8LfINfyjKcXetulatSuW633Bf0shNwX4Pn2DCxS8XsLUqkaY OuRaCF08UWkXzv+zCaYJPeV0BAAvQ3/wRmHe7Adgs57M0ofna1+aMB2bBT0evEXtX4TLgLsmqG7 A4ZNzOgESGWXg8AhPKMYeZOFMu6Y4yEnfTFrS+1EvUxP5dqcxiIJ7Q51Ysz+ROQPC1hklC4IFwB pi+h5SJqv0wVdtAVOIyo7ofIpkRoNpu/pgAG8lBXv8GTv0EtwpXQlFnm+tWqen18ASQ8uNJeapX hJIPbprrQ+ZvTYWkj2wUgCzypFOL0tlaAmOzRRfYY0iW05RZ57Xac1Sx9cdEGdVcgB1v0= X-Developer-Key: i=flavra@baylibre.com; a=openpgp; fpr=8657854F953BDCA31EC314E6EDF13B73CE94365F Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The st_lsm6dsx_hwfifo_odr_store() function, which is called when userspace writes the buffer sampling frequency sysfs attribute, calls st_lsm6dsx_check_odr(), which accesses the odr_table array at index `sensor->id`; since this array is only 2 entries long, an access for any sensor type other than accelerometer or gyroscope is an out-of-bounds access. To prevent userspace from triggering an out-of-bounds array access, and to support the only use case for which FIFO sampling frequency values different from the sensor sampling frequency may be needed (which is for keeping FIFO data rate low while sampling acceleration data at high rates for accurate event detection), do not create the buffer sampling frequency attribute for sensor types other than the accelerometer. Fixes: 6b648a36c200 ("iio: imu: st_lsm6dsx: Decouple sensor ODR from FIFO b= atch data rate") Signed-off-by: Francesco Lavra --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/i= mu/st_lsm6dsx/st_lsm6dsx_buffer.c index 55d877745575..5ac45e6230b5 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -858,12 +858,21 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) int i, ret; =20 for (i =3D 0; i < ST_LSM6DSX_ID_MAX; i++) { + const struct iio_dev_attr **attrs; + if (!hw->iio_devs[i]) continue; =20 + /* + * For the accelerometer, allow setting FIFO sampling frequency + * values different from the sensor sampling frequency, which + * may be needed to keep FIFO data rate low while sampling + * acceleration data at high rates for accurate event detection. + */ + attrs =3D (i =3D=3D ST_LSM6DSX_ID_ACC) ? st_lsm6dsx_buffer_attrs : NULL; ret =3D devm_iio_kfifo_buffer_setup_ext(hw->dev, hw->iio_devs[i], &st_lsm6dsx_buffer_ops, - st_lsm6dsx_buffer_attrs); + attrs); if (ret) return ret; } --=20 2.39.5 From nobody Sun Feb 8 07:07:47 2026 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 4FE5F366557 for ; Fri, 9 Jan 2026 18:15:37 +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=1767982538; cv=none; b=JDwyMe8O+8ZjpjKVCjYwwDhi126gkredsAwXV/NZBb86p2ptbHBtQTZEwji3Paw4tB259NLVzToYYEL370TR3/ROnrmaVkQarwv8fBbsmH5IomUGwnrSdF6dzZZuJLOdo8EUbBMn3nzCrC44mvxNVRP9HinDTvwBQFuswx0Ip24= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767982538; c=relaxed/simple; bh=HyDQvFt38CbL24666SIbmPISPjsBCOGkvrEjkNdUEYM=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AoKovHzy1hNAjvWC7V6HWSVOGycU/R0fl7FMOEq7NCLaEwJo62SoBBP+9ipkR9zNC8CX9/ys2rgs3N/00k75VqFd4jcrF8Y8eZUGLsZBy7O9O4wInoLH/OoxoOlGsX9ZK/iFEGVrVreNRK30JISM02VQPRY1KncKz+mrn+IxNZk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=NnKNyeqr; arc=none smtp.client-ip=209.85.208.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="NnKNyeqr" Received: by mail-ed1-f52.google.com with SMTP id 4fb4d7f45d1cf-64c893f3a94so5263811a12.0 for ; Fri, 09 Jan 2026 10:15:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1767982536; x=1768587336; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=jNKSanGi/682T6/bpK1636gCehsHDuuGDNYO8lX6fUQ=; b=NnKNyeqroKLkE2zQ779Kfmyc9snzuvfWVB/2zayT0v/80DEzE4jLXHXzZ6t2jw9bvI i6x3XEBuUTeDeTxfg7h+OuKxecPre4vUaDpFuPfjtKEmouCiT5Rvpp86FTbGlF2QrL+/ AQzI0RBvt3DojRpzK6kTISxS0zZGj2SM9SOnGKhfzA3C0AGFeniSYaE6rZxC3C6E1xaL E6KDXCztqIRfDIRYr8M4rEZcN53Na2sixbBxNv73TUKhymTUhuBMmeDA2dp+66m3bWxk 19rPaMNq5zi1unlBZYtuUzehprCJkLzWxTpO88jK0qlKGjDK6REACWyFffpGmsnhXdAO DJCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982536; x=1768587336; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=jNKSanGi/682T6/bpK1636gCehsHDuuGDNYO8lX6fUQ=; b=aVQeQKDy5Sy85ZfEtA3udlakqcpzr7l9BAtT8vz9+IaNxxwOyVy8IPvTRVuFkrcpBA DBXVT6Xk30uK2lZWrQkgrSHqr5s7mRlrHUJcy19GEfW6rC8+nwKDw4z3RQeiZW8agDFI tNUFsZwXbH+IVg1mTgrMRjOMemRI/DE8vpTr1pIB1RN5GB1Mc6I/zOLhnIwUQT7U9um9 J8sXH0izIWhmQKqwco6sIJDdgvLc1MXN4Yvc8yXeBEq+nXfBPpfqZ6av7ele4PD4uawI bn+pDy0Oz46fQly5ZUmNhHucH2x32/qN1ILwPi+7JhRoWvkTVy+MKoTdtxYOhka909yu OckA== X-Forwarded-Encrypted: i=1; AJvYcCWzxRMEl4/LOMkAOM+nZ345uIRBqjsJVfUP3D9Ejev4fTFIBsJN6KaV3wO/9hxIJ+RTNQu119zYbYNxfy4=@vger.kernel.org X-Gm-Message-State: AOJu0YxhvhB5iUmT8VynMmAFE+wdJajZoe6fdzRUuFamUWJh7D60mfO+ 5hosAWu8OgXegzpbylO9FmR6IjupW4I+BdDQifa1QGRyoZvQ7VbCI8dWZCE7lPnZSFw= X-Gm-Gg: AY/fxX4on4lOC/smZCu3kF8xeW+oSS+0LCB4QPMSbTWRdZU5T4ZuAz7HBdQKfJ6i1Tl lxTdbJwgYQ2hwSXKlfLmqfOlbkcnTK/CVj3n0P6WyDKrGHu7pTC0ZpnLOm3qWo2OoqUxzIvf1y1 /RGW0RZmG2aXLRdAFKJDfbWi7LyqV50HAzKGEg8s1O00HkbtjK5upUnrjO0jz5sVpZAisK2dp8q GP2aMMcDXuXMVnzhrdiXuj+jmQqzQrpkLOj4pNE1uAoi/CYUMeHklhorpdbmpwDucUcWfelI1Aw 2MUR7wpZRffhIvFTvsEdWpff7VG7iG/hHImCKD8Oveydudflbq7KGmlJ1o09hQsEl4jwmnnU8MP RoXKxinomob2aIPcviM2X0QhC1MvyUn6fCByll3CjcuiTxuq56GT6+6K/OQ== X-Google-Smtp-Source: AGHT+IEdAr73dmVnN674sxfFpbGODRqcsy8dZfQgBLgbGjQzIlujJ+Urus5GqDJjCqurPfWcvbCuOQ== X-Received: by 2002:a17:907:971d:b0:b80:3ff7:e43d with SMTP id a640c23a62f3a-b8444faa4femr1109183766b.26.1767982535706; Fri, 09 Jan 2026 10:15:35 -0800 (PST) Received: from localhost ([151.47.174.220]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b842a4cfe6bsm1174309566b.34.2026.01.09.10.15.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:15:35 -0800 (PST) From: Francesco Lavra To: Lorenzo Bianconi , Jonathan Cameron , David Lechner , =?UTF-8?q?Nuno=20S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/3] iio: imu: st_lsm6dsx: set FIFO ODR for accelerometer and magnetometer only Date: Fri, 9 Jan 2026 19:15:27 +0100 Message-Id: <20260109181528.154127-3-flavra@baylibre.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260109181528.154127-1-flavra@baylibre.com> References: <20260109181528.154127-1-flavra@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1725; i=flavra@baylibre.com; h=from:subject; bh=HyDQvFt38CbL24666SIbmPISPjsBCOGkvrEjkNdUEYM=; b=owEB7QES/pANAwAKAe3xO3POlDZfAcsmYgBpYUWGk8yDBpa5cnHA5yE2LmLq9JwJ7/3Z7nuTl Ak+T8zMK/2JAbMEAAEKAB0WIQSGV4VPlTvcox7DFObt8TtzzpQ2XwUCaWFFhgAKCRDt8TtzzpQ2 XymmC/9F2DC5VZETvTqxNEzTvp8IPesMArEGV9mIXgu3f8Yg6KfzKa/xNifgCmH7NghoMeMIPpq F/DZnPYO7foWKEuCJ5d3pP9FNZ0+a8pe4wgpmGsHugtkI6wqtAjS2AaJp/0kfDokLodSu7EFwvP xqbcbkCC5esPEygIoUO0cWCeJPjw/4r/rN8QWOPY/YPZjLA8PMZkVjg3FWGk5p9Mi8+ujIeGiCR zKv7Xhtk8yX+yOWJklFqjo0BgUgrzsbIsO1JemYhkaFWVGx2vvbiljBQ5azsJGzRqs8Z3kDbsRw 0qVbafSIHisScaszRNO0hg0LkbEeULnPR9bAUCbPMWbOTS9ejGdVtObQW9bzbunbLJsYsio5/5o miI27lYfAlHHTF+kl9Z8Qqyu7BX2U5D+0sVOnlFaNCU7N8AyXi8RBVS5K0cYPMbvPmx2V9OlkM7 LVN2Lj67FSXetieHNATuqnw4zCAIMa//68w1ufgVAXVCPSNp/z51Sv3jpyAPqf3CXkpQM= X-Developer-Key: i=flavra@baylibre.com; a=openpgp; fpr=8657854F953BDCA31EC314E6EDF13B73CE94365F Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The st_lsm6dsx_set_fifo_odr() function, which is called when enabling and disabling the hardware FIFO, checks the contents of the hw->settings->batch array at index sensor->id, and then sets the current ODR value in sensor registers that depend on whether the register address is set in the above array element. This logic is valid for internal sensors only, i.e. the accelerometer and magnetometer; however, since commit c91c1c844ebd ("iio: imu: st_lsm6dsx: add i2c embedded controller support"), this function is called also when configuring the hardware FIFO for external sensors (i.e. sensors accessed through the sensor hub functionality), which can result in unrelated device registers being written. Add a check to the beginning of st_lsm6dsx_set_fifo_odr() so that it does not touch any registers unless it is called for internal sensors. Fixes: c91c1c844ebd ("iio: imu: st_lsm6dsx: add i2c embedded controller sup= port") Signed-off-by: Francesco Lavra --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/i= mu/st_lsm6dsx/st_lsm6dsx_buffer.c index 5ac45e6230b5..9db48e835d4f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -225,6 +225,9 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_se= nsor *sensor, const struct st_lsm6dsx_reg *batch_reg; u8 data; =20 + /* Only accel and gyro have batch registers. */ + if (sensor->id >=3D ARRAY_SIZE(hw->settings->batch)) + return 0; batch_reg =3D &hw->settings->batch[sensor->id]; if (batch_reg->addr) { int val; --=20 2.39.5 From nobody Sun Feb 8 07:07:47 2026 Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5628D3644C6 for ; Fri, 9 Jan 2026 18:15:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767982546; cv=none; b=KY5R3dENT36ph66fIn9+tnNIWO/vcXK+fr/7PhvKu1G78vv2/5xt1m7XovrJ5WJkLCh8ZoHKsXaoG5lJTsRPaNDLiCOip8kzs19wymk5fbFZ2E+cnhqixV+JUBdC1IcDPTLm9iCZBbZmNQGLXwkBbXT6qMcDYPBbLlkyd1X0iak= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767982546; c=relaxed/simple; bh=uFBxumFSEetS4mSalFZ/zL1Y9qeJabYRpftECntiDEY=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=p6ugbt2Fd5UWgn/+TyDZPfrInoATYrNj2tP1RgHiGHPKJHh3snhQTX9bm7VXmFAqmdHCecSTGXpRk1qo33Q26HdUipc3PGlTJZcdoq6nJ+9u1vXGJfsgKHV1kHhjfXgvJtnXjrf73taJMLGDdulnfKH1MEV7ZQCbN1KgOEl9fZE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=lJ9pcmLa; arc=none smtp.client-ip=209.85.208.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="lJ9pcmLa" Received: by mail-ed1-f49.google.com with SMTP id 4fb4d7f45d1cf-64ba74e6892so7555504a12.2 for ; Fri, 09 Jan 2026 10:15:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1767982538; x=1768587338; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=cA0pkq9okEx5S2Ht3vwZjCEQpQSyWv6klnEDD6B9/MM=; b=lJ9pcmLaZloeOjpJ+CVwy+4Db4xE1zBMmZWZpf0r5JqUHaZfu0rKxeAAST/oiXiCp/ KndxDyI69I3VYpoZNucDn6WIlDVnAiI//6skvEh+mF0ghTrR2H3X0tAUHXCNp5EqofI6 maJD1emhqLfRDoOWG3Ld7odbsflqqwZsT5seoBOO8HeHfCmQ3/o+W9G9YJHabH6FxAA6 6RdbcoPPOam4zLGRqq04Xb6ug2Xxi3PyYuUD3YQrmEENlCagWL5fU4d47JCgED5kSUsc bthpeSqWlUj4plRFqbG7QBy8xVISCyAboNEJ57dIxUpxTKr1MAyUyLMGNxQQGPRtWXpG iR9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982538; x=1768587338; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=cA0pkq9okEx5S2Ht3vwZjCEQpQSyWv6klnEDD6B9/MM=; b=DSNzq2v0cPxicrAVt5Rt0viVwv+2g3wk8uaaSdxYVy5bP/XlNiw0ZHbrABYH9W/Wmf Z63sAOBquJtfZEriOkHW+w+qa5paeAAOO6u7qifddS/QHkp5ZB8bMExeenCfoLVG0CRY 2fGv4TSjPO+yP4pwsT7eDBbykoX6DW+qISFV+xn0nb2UuJDAQpVt0v2i0h6P2sFyqsjB 3AcKg8Pc/6CG5wMfw/c8z+NuHGmmAthNGCnLRiS0hy0YJuCmq80vRncHFYtAoyUm3e7y KEeIy7jIH/ZL21J1HngSjbuj064pGmX8juSKQgi3+dlyTjAqFxqVhy6mh0ktqSeHKz5O 60QA== X-Forwarded-Encrypted: i=1; AJvYcCW7L6yW9aY6VH0KPrpkCB0MCq7ki5HS4dVbhPtp4oPo8Wno3tWSO9Srw7IKFA9FuZl/f3si76uLLGwjYbU=@vger.kernel.org X-Gm-Message-State: AOJu0YwhUPc58jC0/0+5GxhzbEzlNE26JrFgt1Txhv+mJplL+ePoAKwu bdDFlcGOCueluD/svW85bFV5dYK+dtv/0v303cn5ZkxdLEl3Xn6NVffpRGINYN2bgv8= X-Gm-Gg: AY/fxX7AULplgjNjIxdVdCDv/Diu49pim7WGdKsE0r9YudiZVCQOZ9oHDj6JZv5YQEX AwLucZ1v4LMDlVHcPfxEAhuwLXsxqltd/8KBlcIziRKjh5swU/fd1UpT6eb5+BPZScj9vuToSO2 1a7KPI380k4yAyEg8Zw8oyDzD30w3t5hsFwOOnrJT5p5ZZjnUr0hUWU0vO6R0HuChrOK8LjYhky QSA0A5tlLBGzAqsqiUh5bWxXhrfqkQS51nQxc0fH/g2wq9h3PJNas1LyR3Ut1sdvPGctl4bfRXm aEC/IRHsEH8YWN6DRB5zoofaGnAfPmEmzHS82TaQYbVk+DpsCWMRw09V0HZaqMAc/UzB2JFB99N PWSGjQd7v8oHuRzo5isvyDuBw6cWVeIr2hrZWlBllJmHenjetPhLknakpm4yrHDvAKSNRXEw8oy Q7hA== X-Google-Smtp-Source: AGHT+IFJAkZWNMFKEkNzH1Ew9l2kgojtVvTf3F/+Lt5XSfD27tTOOeruXPZoHnZkDq6iYmYGAwEAfA== X-Received: by 2002:a05:6402:3550:b0:64b:a1e6:8018 with SMTP id 4fb4d7f45d1cf-65097e8e46fmr8779291a12.31.1767982537600; Fri, 09 Jan 2026 10:15:37 -0800 (PST) Received: from localhost ([151.47.174.220]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-6507b8c3f89sm11212611a12.5.2026.01.09.10.15.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:15:37 -0800 (PST) From: Francesco Lavra To: Lorenzo Bianconi , Jonathan Cameron , David Lechner , =?UTF-8?q?Nuno=20S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/3] iio: imu: st_lsm6dsx: add support for rotation sensor Date: Fri, 9 Jan 2026 19:15:28 +0100 Message-Id: <20260109181528.154127-4-flavra@baylibre.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260109181528.154127-1-flavra@baylibre.com> References: <20260109181528.154127-1-flavra@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=15068; i=flavra@baylibre.com; h=from:subject; bh=uFBxumFSEetS4mSalFZ/zL1Y9qeJabYRpftECntiDEY=; b=owEB7QES/pANAwAKAe3xO3POlDZfAcsmYgBpYUWHL500O1lbMklxs5A1DwTf/4/8bR4fTJBIG yGUtNwg4PuJAbMEAAEKAB0WIQSGV4VPlTvcox7DFObt8TtzzpQ2XwUCaWFFhwAKCRDt8TtzzpQ2 X4kMC/4nlLcoUoznnlzThvEQhlPGhIbBlPFXP/LI58uixZSge+Zmt7Cjp4leqq82h9Nv5yVzU7y lobdVfVI0UCtIrPgAt9R4F/oBsSUJ+/YDHuGdS0c6QQgdUuP5Ijd8be8gbv6OvNqvyz/5sg5oia RDDCbNphfnsxZT/WLMqow0s5mmuyUjGZy2I/tNG0g4dvhELMFRLazaWdwfPCWSEgEYn+1dd9y/2 zJ/ZRvNg5+TbLSXOFEXC9udo3OGwXBqE9uc0D8Ml1KuicJjeiv2xaD4g0v3VFHyGm1XHj8ZcqIW ekdfiy5JcyajQj3klPdfL2pmkdvqFBo6GIYH7gymBeLkVingYkZYTeedcGGqfG+yVkhk3j+IauE q+kgn4MdJaiQdvvcVn8fg7mCCQsSU0fRjZ1FzwVllyImTz8Tl49DpqgTQatdIivTy+1mhA+XkWs znKs0VkLl166ZndMptispUlOkoQrIWNYBYlq7bv/AQ8gLdciXcsORGt11xYrtmCCTTSVA= X-Developer-Key: i=flavra@baylibre.com; a=openpgp; fpr=8657854F953BDCA31EC314E6EDF13B73CE94365F Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some IMU chips in the LSM6DSX family have sensor fusion features that combine data from the accelerometer and gyroscope. One of these features generates rotation vector data and makes it available in the hardware FIFO as a quaternion (more specifically, the X, Y and Z components of the quaternion vector, expressed as 16-bit half-precision floating-point numbers). Add support for a new sensor instance that allows receiving sensor fusion data, by defining a new struct st_lsm6dsx_sf_settings (which contains chip-specific details for the sensor fusion functionality), and adding this struct as a new field in struct st_lsm6dsx_settings. In st_lsm6dsx_core.c, populate this new struct for the LSM6DSV and LSM6DSV16X chips, and add the logic to initialize an additional IIO device if this struct is populated for the hardware type being probed. Note: a new IIO device is being defined (as opposed to adding channels to an existing device) because each of the existing devices handles data coming from a single sensor, while sensor fusion data comes from multiple sensors. Tested on LSMDSV16X. Signed-off-by: Francesco Lavra --- drivers/iio/imu/st_lsm6dsx/Makefile | 2 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 26 +- .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 16 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 58 +++++ .../iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c | 224 ++++++++++++++++++ 5 files changed, 319 insertions(+), 7 deletions(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6d= sx/Makefile index 57cbcd67d64f..19a488254de3 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only st_lsm6dsx-y :=3D st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ - st_lsm6dsx_shub.o + st_lsm6dsx_shub.o st_lsm6dsx_fusion.o =20 obj-$(CONFIG_IIO_ST_LSM6DSX) +=3D st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) +=3D st_lsm6dsx_i2c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_l= sm6dsx/st_lsm6dsx.h index 07b1773c87bd..4173f670f7af 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -294,6 +294,7 @@ enum st_lsm6dsx_sensor_id { ST_LSM6DSX_ID_EXT0, ST_LSM6DSX_ID_EXT1, ST_LSM6DSX_ID_EXT2, + ST_LSM6DSX_ID_SF, ST_LSM6DSX_ID_MAX, }; =20 @@ -301,6 +302,15 @@ enum st_lsm6dsx_ext_sensor_id { ST_LSM6DSX_ID_MAGN, }; =20 +struct st_lsm6dsx_sf_settings { + const struct iio_chan_spec *chan; + int chan_len; + struct st_lsm6dsx_odr_table_entry odr_table; + struct st_lsm6dsx_reg fifo_enable; + struct st_lsm6dsx_reg page_mux; + struct st_lsm6dsx_reg enable; +}; + /** * struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings * @i2c_addr: I2c slave address list. @@ -388,6 +398,7 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_hw_ts_settings ts_settings; struct st_lsm6dsx_shub_settings shub_settings; struct st_lsm6dsx_event_settings event_settings; + struct st_lsm6dsx_sf_settings sf_settings; }; =20 enum st_lsm6dsx_sensor_id { @@ -510,6 +521,9 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sens= or, u32 odr, u8 *val); int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name); int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enab= le); int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int le= n); +int st_lsm6dsx_sf_probe(struct st_lsm6dsx_hw *hw, const char *name); +int st_lsm6dsx_sf_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable= ); +int st_lsm6dsx_sf_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable); =20 static inline int @@ -564,12 +578,14 @@ st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio= _dev, static inline int st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) { - if (sensor->id =3D=3D ST_LSM6DSX_ID_EXT0 || - sensor->id =3D=3D ST_LSM6DSX_ID_EXT1 || - sensor->id =3D=3D ST_LSM6DSX_ID_EXT2) + switch (sensor->id) { + case ST_LSM6DSX_ID_EXT0 ... ST_LSM6DSX_ID_EXT2: return st_lsm6dsx_shub_set_enable(sensor, enable); - - return st_lsm6dsx_sensor_set_enable(sensor, enable); + case ST_LSM6DSX_ID_SF: + return st_lsm6dsx_sf_set_enable(sensor, enable); + default: + return st_lsm6dsx_sensor_set_enable(sensor, enable); + } } =20 static const diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/i= mu/st_lsm6dsx/st_lsm6dsx_buffer.c index 9db48e835d4f..a689c081c186 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -88,6 +88,7 @@ enum st_lsm6dsx_fifo_tag { ST_LSM6DSX_EXT0_TAG =3D 0x0f, ST_LSM6DSX_EXT1_TAG =3D 0x10, ST_LSM6DSX_EXT2_TAG =3D 0x11, + ST_LSM6DSX_ROT_TAG =3D 0x13, }; =20 static const @@ -226,8 +227,11 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_s= ensor *sensor, u8 data; =20 /* Only accel and gyro have batch registers. */ - if (sensor->id >=3D ARRAY_SIZE(hw->settings->batch)) + if (sensor->id >=3D ARRAY_SIZE(hw->settings->batch)) { + if (sensor->id =3D=3D ST_LSM6DSX_ID_SF) + return st_lsm6dsx_sf_set_odr(sensor, enable); return 0; + } batch_reg =3D &hw->settings->batch[sensor->id]; if (batch_reg->addr) { int val; @@ -579,6 +583,16 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, = u8 tag, case ST_LSM6DSX_EXT2_TAG: iio_dev =3D hw->iio_devs[ST_LSM6DSX_ID_EXT2]; break; + case ST_LSM6DSX_ROT_TAG: + /** + * The sensor reports only the {X, Y, Z} elements of the + * quaternion vector; set the W value to 0 (it can be derived + * from the {X, Y, Z} values due to the property that the vector + * is normalized). + */ + *(u16 *)(data + ST_LSM6DSX_SAMPLE_SIZE) =3D 0; + iio_dev =3D hw->iio_devs[ST_LSM6DSX_ID_SF]; + break; default: return -EINVAL; } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu= /st_lsm6dsx/st_lsm6dsx_core.c index dc0ae0e488ce..c21163a06a71 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -94,6 +94,24 @@ =20 #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f =20 +/* Raw values from the IMU are 16-bit half-precision floating-point number= s. */ +#define ST_LSM6DSX_CHANNEL_ROT \ +{ \ + .type =3D IIO_ROT, \ + .modified =3D 1, \ + .channel2 =3D IIO_MOD_QUATERNION, \ + .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index =3D 0, \ + .scan_type =3D { \ + .sign =3D 'u', \ + .realbits =3D 16, \ + .storagebits =3D 16, \ + .endianness =3D IIO_LE, \ + .repeat =3D 4, \ + }, \ + .ext_info =3D st_lsm6dsx_ext_info, \ +} + #define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */ =20 static const struct iio_chan_spec st_lsm6dsx_acc_channels[] =3D { @@ -153,6 +171,11 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_chan= nels[] =3D { IIO_CHAN_SOFT_TIMESTAMP(3), }; =20 +static const struct iio_chan_spec st_lsm6dsx_sf_channels[] =3D { + ST_LSM6DSX_CHANNEL_ROT, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] =3D { { .reset =3D { @@ -1492,6 +1515,35 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_s= ensor_settings[] =3D { .wakeup_src_y_mask =3D BIT(1), .wakeup_src_x_mask =3D BIT(2), }, + .sf_settings =3D { + .chan =3D st_lsm6dsx_sf_channels, + .chan_len =3D ARRAY_SIZE(st_lsm6dsx_sf_channels), + .odr_table =3D { + .reg =3D { + .addr =3D 0x5e, + .mask =3D GENMASK(5, 3), + }, + .odr_avl[0] =3D { 15000, 0x00 }, + .odr_avl[1] =3D { 30000, 0x01 }, + .odr_avl[2] =3D { 60000, 0x02 }, + .odr_avl[3] =3D { 120000, 0x03 }, + .odr_avl[4] =3D { 240000, 0x04 }, + .odr_avl[5] =3D { 480000, 0x05 }, + .odr_len =3D 6, + }, + .fifo_enable =3D { + .addr =3D 0x44, + .mask =3D BIT(1), + }, + .page_mux =3D { + .addr =3D 0x01, + .mask =3D BIT(7), + }, + .enable =3D { + .addr =3D 0x04, + .mask =3D BIT(1), + }, + }, }, { .reset =3D { @@ -2899,6 +2951,12 @@ int st_lsm6dsx_probe(struct device *dev, int irq, in= t hw_id, return err; } =20 + if (hw->settings->sf_settings.chan) { + err =3D st_lsm6dsx_sf_probe(hw, name); + if (err) + return err; + } + if (hw->irq > 0) { err =3D st_lsm6dsx_irq_setup(hw); if (err < 0) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c b/drivers/iio/i= mu/st_lsm6dsx/st_lsm6dsx_fusion.c new file mode 100644 index 000000000000..7c78f14cbb91 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics st_lsm6dsx IMU sensor fusion + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static int +st_lsm6dsx_sf_get_odr_val(const struct st_lsm6dsx_sf_settings *settings, + u32 odr, u8 *val) +{ + int i; + + for (i =3D 0; i < settings->odr_table.odr_len; i++) { + if (settings->odr_table.odr_avl[i].milli_hz =3D=3D odr) + break; + } + if (i =3D=3D settings->odr_table.odr_len) + return -EINVAL; + + *val =3D settings->odr_table.odr_avl[i].val; + return 0; +} + +/** + * st_lsm6dsx_sf_set_page - Enable or disable access to sensor fusion + * configuration registers. + * @hw: Sensor hardware instance. + * @enable: True to enable access, false to disable access. + * + * The register page lock is acquired when enabling access, and released w= hen + * disabling access. Therefore, a function call with @enable set to true m= ust be + * followed by a call with @enable set to false (unless the first call ret= urns + * an error value). + * + * Return: 0 on success, negative value on error. + */ +static int st_lsm6dsx_sf_set_page(struct st_lsm6dsx_hw *hw, bool enable) +{ + const struct st_lsm6dsx_reg *mux; + int err; + + mux =3D &hw->settings->sf_settings.page_mux; + if (enable) + mutex_lock(&hw->page_lock); + err =3D regmap_assign_bits(hw->regmap, mux->addr, mux->mask, enable); + if (!enable || err < 0) + mutex_unlock(&hw->page_lock); + + return err; +} + +int st_lsm6dsx_sf_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) +{ + struct st_lsm6dsx_hw *hw =3D sensor->hw; + const struct st_lsm6dsx_reg *enable_reg; + int err; + + enable_reg =3D &hw->settings->sf_settings.enable; + err =3D st_lsm6dsx_sf_set_page(hw, true); + if (err < 0) + return err; + + err =3D regmap_assign_bits(hw->regmap, enable_reg->addr, enable_reg->mask, + enable); + st_lsm6dsx_sf_set_page(hw, false); + + return err; +} + +int st_lsm6dsx_sf_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable) +{ + struct st_lsm6dsx_hw *hw =3D sensor->hw; + const struct st_lsm6dsx_sf_settings *settings; + u8 data; + int err; + + err =3D st_lsm6dsx_sf_set_page(hw, true); + if (err < 0) + return err; + + settings =3D &hw->settings->sf_settings; + if (enable) { + u8 odr_val; + const struct st_lsm6dsx_reg *reg =3D &settings->odr_table.reg; + + st_lsm6dsx_sf_get_odr_val(settings, sensor->hwfifo_odr_mHz, + &odr_val); + data =3D ST_LSM6DSX_SHIFT_VAL(odr_val, reg->mask); + err =3D regmap_update_bits(hw->regmap, reg->addr, reg->mask, + data); + if (err < 0) + goto out; + } + err =3D regmap_assign_bits(hw->regmap, settings->fifo_enable.addr, + settings->fifo_enable.mask, enable); + +out: + st_lsm6dsx_sf_set_page(hw, false); + + return err; +} + +static int st_lsm6dsx_sf_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + struct st_lsm6dsx_sensor *sensor =3D iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val =3D sensor->hwfifo_odr_mHz / MILLI; + *val2 =3D (sensor->hwfifo_odr_mHz % MILLI) * MILLI; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int st_lsm6dsx_sf_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct st_lsm6dsx_sensor *sensor =3D iio_priv(iio_dev); + const struct st_lsm6dsx_sf_settings *settings; + int err; + + settings =3D &sensor->hw->settings->sf_settings; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: { + u32 odr_mHz; + u8 odr_val; + + odr_mHz =3D val * MILLI + val2 / MILLI; + err =3D st_lsm6dsx_sf_get_odr_val(settings, odr_mHz, &odr_val); + if (err) + return err; + + sensor->hwfifo_odr_mHz =3D odr_mHz; + break; + } + default: + return -EINVAL; + } + + return 0; +} + +static ssize_t st_lsm6dsx_sf_sampling_freq_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct st_lsm6dsx_sensor *sensor =3D iio_priv(dev_to_iio_dev(dev)); + const struct st_lsm6dsx_sf_settings *settings; + int i, len =3D 0; + + settings =3D &sensor->hw->settings->sf_settings; + for (i =3D 0; i < settings->odr_table.odr_len; i++) { + u32 val =3D settings->odr_table.odr_avl[i].milli_hz; + + len +=3D scnprintf(buf + len, PAGE_SIZE - len, "%lu.%03lu ", + val / MILLI, val % MILLI); + } + buf[len - 1] =3D '\n'; + + return len; +} + +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sf_sampling_freq_avail); +static struct attribute *st_lsm6dsx_sf_attributes[] =3D { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_lsm6dsx_sf_attribute_group =3D { + .attrs =3D st_lsm6dsx_sf_attributes, +}; + +static const struct iio_info st_lsm6dsx_sf_info =3D { + .attrs =3D &st_lsm6dsx_sf_attribute_group, + .read_raw =3D st_lsm6dsx_sf_read_raw, + .write_raw =3D st_lsm6dsx_sf_write_raw, + .hwfifo_set_watermark =3D st_lsm6dsx_set_watermark, +}; + +int st_lsm6dsx_sf_probe(struct st_lsm6dsx_hw *hw, const char *name) +{ + const struct st_lsm6dsx_sf_settings *settings; + struct st_lsm6dsx_sensor *sensor; + struct iio_dev *iio_dev; + + iio_dev =3D devm_iio_device_alloc(hw->dev, sizeof(*sensor)); + if (!iio_dev) + return -ENOMEM; + + settings =3D &hw->settings->sf_settings; + sensor =3D iio_priv(iio_dev); + sensor->id =3D ST_LSM6DSX_ID_SF; + sensor->hw =3D hw; + sensor->hwfifo_odr_mHz =3D settings->odr_table.odr_avl[0].milli_hz; + sensor->watermark =3D 1; + iio_dev->modes =3D INDIO_DIRECT_MODE; + iio_dev->info =3D &st_lsm6dsx_sf_info; + iio_dev->channels =3D settings->chan; + iio_dev->num_channels =3D settings->chan_len; + scnprintf(sensor->name, sizeof(sensor->name), "%s_sf", name); + iio_dev->name =3D sensor->name; + + /** + * Put the IIO device pointer in the iio_devs array so that the caller + * can set up a buffer and register this IIO device. + */ + hw->iio_devs[ST_LSM6DSX_ID_SF] =3D iio_dev; + + return 0; +} --=20 2.39.5