From nobody Mon Sep 28 21:03:43 2026 Received: from mail-lj1-f182.google.com (mail-lj1-f182.google.com [209.85.208.182]) (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 A7087463B74 for ; Mon, 17 Aug 2026 17:08:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786986497; cv=none; b=IX/Umjro1EDgt5LdqoVQ3Z0HvH7RJ2j0hjgIhoKBbbLlxQAA5Adzgnl4r4o2DIVZlVJs4f+N+61+bZ2O4pnV4de+NcKVpo2vwpmooGrhfSxkOMxPgIB9AJaLrJs8u44Mr0cwzc7SN4P6g86jUWAS9S0jUIRWxxONhKr0w++1kRw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786986497; c=relaxed/simple; bh=NlqrtaF1jvx4fxtT+Rln6rcHZtm9m2tvcwizoBcGjAs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QuRwVPeK3cVoSB1vjyusSrw2QYltuzJrJOLbTqqPDYVlptSP+kqHXAbt3OTBpKtRwARJoG7cJkvJDD5AdUwf8p8VBqCcjuRppXIRyozg37y0Kzz5HIKEQLxrFDXJ30F/689cZrqU677piUt7zO6YRrAUd1eLcQ6UBRBsKFMoLpo= 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=Y+0zKY8R; arc=none smtp.client-ip=209.85.208.182 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="Y+0zKY8R" Received: by mail-lj1-f182.google.com with SMTP id 38308e7fff4ca-3a12ffc112cso1050361fa.0 for ; Mon, 17 Aug 2026 10:08:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786986494; x=1787591294; 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:content-type; bh=dnqUISuF1GqxCyfBU21SiazIrKDqoxo6IB2fRQd9Di0=; b=Y+0zKY8RnZ6dgFF4KdgKr/rQa4DpiHD+fKERC8vpJ4r3biQq3AgQRaHxocojLYmFj+ YstU3/5JumLztO4F+Dsuez8E4BJSZfa8rcq08aYEdmQPJaA5otqzba0zfdCh/+sU267s XtlpQ4f7YyDRRzRRYRg+C6n61RNSzfEuuVul4FEHtj0iDq477YKfB1+4Gu+5oStD4tWK OJsM+VQrCOyHFkymk3baekKNg/nQyI5+ZXKBVCUPj3bDLW5a5KAtFmq74Gh8JmerPLrn oCUXyYE9GATRlhVr06d0M4px//GR+Nl60Ho6VtXF1mr8ALSlgW6k+NrauNtgqbLID3Ni I7Zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786986494; x=1787591294; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=dnqUISuF1GqxCyfBU21SiazIrKDqoxo6IB2fRQd9Di0=; b=GdqhmFy2Bg98EGzLOLNkWvCEcYST0CmeyilQYk0MRBLoIi/YqBY4sxPxDWDfWlY6fq vRMH477RDtAYxGdIjihy+IJ2mz6/hVRlPqL6pUiv0e/FeQTcv5r/0TG2YxpUDMzfINJp TFOkZE5By3dqvhqfjegokYnKgVq9+TOIS0N+h5aHwxILaQEeWGxaH2EgfTCcbzrkiDBE UhyMuSSs6kgNEuxoQJ+fSjxcWwdPGZSKEwttD05EeHZvRvbGjVlqXuA7mC3i5HkKbUsv qX2x5owPolZgyHXEbYxLa/dLkXU9l5OiP9UNQv9UagcBxXyFNnE+gf1blJxEM9k8fkGM cR7Q== X-Forwarded-Encrypted: i=1; AHgh+RoIluRe5Sd7aU7u4Z4C0Fb2iq5aj+3DqJlCpCP2i2PNXaPZNBK+j59zgbgulmzMh7qk6/6SPXpjieED3JQ=@vger.kernel.org X-Gm-Message-State: AOJu0YzOh69lnVbyqJgNpF6gjVRpYOl4wIQb8Km1OGyu5scJF/NI6JdY KRaITUUpY2mjF8n6rf6SWyZ8hWQOj0F1+AuiMF7umo3YDt+uIuni3R9m X-Gm-Gg: AR+sD10mxd0DL8TfobipDySxuLunBlLJWuXo7Zvg5koPyldVphQIwo75h5qwaLwNbk5 asDn+wSefjUrDX/LPYAXowWf6L/3bjPwYi6vnXMxi1zgnquqANGL+QS7UVDoUcdWUtgzxfCx944 J9WixtpMSQvirFiD2GzpTB9biWV4MrjR3yd06SFzu8K7Gv6EavKtjYehwe1kGMnFQ4IRtpZIx4/ j5nvlJfVGJmjg+8y3+d6oRu68gAeWdEZWwFboYpFF3S26ib9i/0zCCV5K8QU+R9XuLpAoTwbXy+ 14l/5idOAhKm8bC4RAd9JWnXALEnIVkhUsHKm15zMY732Codt0VjDuiGLWem4C6wkDNkewiimhk n4WYK/2TLXM2wnGz17bS/nHGAYv8mSC9uHgwLnuIQEIo1XhbdOaJL52E02zvj4G38BYxOvBOIC7 1m8ehdnNvxw/JX7IK6coR3vkfCwPjTKVPxZKRU38ATJzR3DQJA/Wkwm/q+UGZKBzbxgKP63cJn4 JXO1GfhxJrdn5R2N3Ex6uZELNTlqCn2qFNBTtIV5Q15TtDXbokZfzJ2DZMgotNyygXhTg== X-Received: by 2002:a05:651c:a210:10b0:39f:af21:75b0 with SMTP id 38308e7fff4ca-3a176a18d7amr746881fa.8.1786986493427; Mon, 17 Aug 2026 10:08:13 -0700 (PDT) Received: from yantra.. (dsl-trebng21-58c187-236.dhcp.inet.fi. [88.193.135.236]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-3a16b0e54casm6053841fa.15.2026.08.17.10.08.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Aug 2026 10:08:12 -0700 (PDT) From: Rupesh Majhi To: Andy Shevchenko , David Lechner , Eddie James , Joel Stanley , Jonathan Cameron , =?UTF-8?q?Nuno=20S=C3=A1?= Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Rupesh Majhi , stable@vger.kernel.org Subject: [PATCH v5 1/3] iio: pressure: dps310: fix CFG_REG bit definitions Date: Mon, 17 Aug 2026 20:07:23 +0300 Message-ID: <20260817170725.1074078-2-zoone.rupert@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260817170725.1074078-1-zoone.rupert@gmail.com> References: <20260817170725.1074078-1-zoone.rupert@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" Three of the CFG_REG bit defines do not match the datasheet. P_SHIFT is bit 2, FIFO_EN is bit 1 and SPI_MODE is bit 0, but the driver defines them as BIT(4), BIT(5) and BIT(6). Those three positions are INT_PRS, INT_TMP and INT_FIFO, the measurement ready and FIFO full interrupt enables for the SDO pin. All three have had the wrong value since the driver was added, when only the temperature shift bit had a user. DPS310_PRS_SHIFT_EN got its first user when pressure support was added, and there it is a real bug. The datasheet requires the pressure result bit-shift to be enabled when the oversampling rate is higher than 8 times, so dps310_set_pres_precision() sets it for oversampling ratios of 16 and above. With the wrong definition it leaves P_SHIFT clear and toggles the pressure ready interrupt instead. The result register is then never shifted, so it no longer matches the scale factor the compensation divides by. On a DPS310 breakout, reading in_pressure_input at oversampling 16, 32 and 64 returns -ERANGE, because dps310_calculate_pressure() ends up negative. Oversampling 128 was not observed to be affected. DPS310_FIFO_EN and DPS310_SPI_EN still have no users, so correcting them changes nothing on its own, but the FIFO enable is needed by the hardware FIFO support later in this series. Temperature is not affected, T_SHIFT is bit 3 and DPS310_TMP_SHIFT_EN already matches it. Fixes: ba6ec48e76bc ("iio: Add driver for Infineon DPS310") Fixes: d711a3c7dc82 ("iio: dps310: Add pressure sensing capability") Cc: stable@vger.kernel.org Signed-off-by: Rupesh Majhi --- drivers/iio/pressure/dps310.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index f45af72a0554..68382960382f 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -50,9 +50,9 @@ #define DPS310_CFG_REG 0x09 #define DPS310_INT_HL BIT(7) #define DPS310_TMP_SHIFT_EN BIT(3) -#define DPS310_PRS_SHIFT_EN BIT(4) -#define DPS310_FIFO_EN BIT(5) -#define DPS310_SPI_EN BIT(6) +#define DPS310_PRS_SHIFT_EN BIT(2) +#define DPS310_FIFO_EN BIT(1) +#define DPS310_SPI_EN BIT(0) #define DPS310_RESET 0x0c #define DPS310_RESET_MAGIC 0x09 #define DPS310_COEF_BASE 0x10 --=20 2.43.0 From nobody Mon Sep 28 21:03:43 2026 Received: from mail-lj1-f175.google.com (mail-lj1-f175.google.com [209.85.208.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D3A0463B89 for ; Mon, 17 Aug 2026 17:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786986498; cv=none; b=gE7Y73XMvNtbOSXMMgSjOY7XRcGMeWnajkoSzQ/H+d/Ep+eJXappX2OkORSNtDJTRYNyV4sSlITilj4CBOycpgqomz1MVuG1NWa6Fe423s1aK92Tr6e6uDJWGtp9KQ7JtR8e3UVaqQmugZ0yOC3ibO8yLSx+u00Pqtp8c34rJrc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786986498; c=relaxed/simple; bh=3Gvk4/djZnTobPPb33vz/llgxMNsRTXQjtyqineco/M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UVeY+tgfKNLAOS7MMo3GRPozlBGLgKWIezg/6k0xtjyhTA4vgT4CVbQnektdM+jSFsL7FHoRpLBe9jvmG3u5cJydGUEiyLgHQr5w7hvc/sBiERjA74OoScf5MUT1KFUkqi1uhoN7o6UjcDPDoT/maUtW3UjZDRW5k/MF8JGNwpk= 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=NSzghm49; arc=none smtp.client-ip=209.85.208.175 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="NSzghm49" Received: by mail-lj1-f175.google.com with SMTP id 38308e7fff4ca-39fa5e3a428so907021fa.1 for ; Mon, 17 Aug 2026 10:08:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786986494; x=1787591294; 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:content-type; bh=3khfOXEHHRX/gULBOcNM3D8sraxx0MJ631P1VQlh1zM=; b=NSzghm49fIMlZ3FmjJA2oegDwqnRm8lPPsWGkhlA7nMraM5bjubQdVhTyCJP1PGr5I Kk2qytL1P/PKhQLcmK5JdFjgfBVGgvU6Pu051qo1nvlDL1q17u0QXtf4lxwuRzt37ifi RD0ipDlYr8y/TffheuNywntEezaesPqdxIjTvzGJhhHUAVVNtOxdBL4Tpln5DiCPWIU1 uMmeQNNhC8c/rN17gvhasUvS4YbjZf7HrOYtJs01hmFXFz8b/LYPn57DaTXWwPbezwgQ aL9O/0tJ2V8yOtKY7AwuqIxyJ4Uiab+NIVMx517IyYFkPOiEYjVsfeimPC06FSyCV+Jr YghA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786986494; x=1787591294; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=3khfOXEHHRX/gULBOcNM3D8sraxx0MJ631P1VQlh1zM=; b=ml/Mbj+Xa1mjFAuErqh5K6+7miXU96uDoTXUG6TsuQFp3YrzDQi0PbjsS0GLw70LG6 s1aMQW44XhI/tXb6GD2JRNTnUBDExDUy+Fqe+zYzACTyXLdUGgV/ezm9yVXYIyz5uiAb kFyAfUv3HafO3oJVOwcqwzZdJR8KHT7K4lTgU5aC53gsAAIXioewreiNXifTF6/HMS6N XX2E4ZtViLHrQZkFVcxDiZ9XiPOp+0H4eOE50xvnji7oP78y7gzkQSzHfATdE2/cw10R lzEioLLt/8DsmW068RJs06ED2yNpKWEM94BiKm2ADjzOw0evRyRGAROxc1MkyVDXgBb3 OWOQ== X-Forwarded-Encrypted: i=1; AHgh+RrAsnj/ylvY92a1VM2SaYG4m3HR1V5oIs60oU7/MZucZ7iAe1saOPr+B9NCh5iZvDt+g5ujOEzNC1RjS8I=@vger.kernel.org X-Gm-Message-State: AOJu0YwqPqX7ztz9DbzcrGd1efwf2sNyZvVZ3C9VitmWhwFLwFzbYQ9e PDO+s3TSBITijx6HnkBcciYTLu6KE21FBgpCQ6gYwO0G0ok0TC1SpoMl X-Gm-Gg: AR+sD11OABBx0VBkR3nOPkzXdsYu+0kZKrp89c/VIFOFFXJIke35IYLyflfIYBUpgFw rp2mMU+FL6CImVwA5U/Qqlf/UiQhJYEaKiz8835tppMFtTtPYrXtpeVTC+TvmmQIu13rorIy2GP 2ODQajYKn0skA3ULwaMqak7GhhGDEHqkmdu41+K2Ph0q8kkHnOkRep8jYVpcTjIoBXQ7AhGg4pT SFDKQA3VBkCVI/HU2UMLxeV6IPhSXDDPRUYtp0Wo+eTQydSDOKc7IascsYS+9+UD29CLi2ItLpW CWoEs8EdPSzClmqopUKdoBmwAJwHGfzROC5Tu8D+MlW6SJrv98xDQUYKflK/KmWk5mxxXjlu+8j v1N+5KsTnc7lhfrHfAx6U1Ntpw7fQ6QMsscg1QoxeXojNASQcdx9krswW4kzaeBPYiC0nhmYvDY jhn+bj+Pnkq3m8VnBlE5GAOfgwEiCvuWTO1vXvE8olGG3LKwhN4KXAbMcVjgeIMlECdjleNE0/H RV4GrzthrlbqLDUy+INcWQ874V9HiNs4vjEp8nX6oEs4IHafsL/Xu+QECY= X-Received: by 2002:a05:651c:43d0:20b0:38e:8357:c5ae with SMTP id 38308e7fff4ca-3a176a46b94mr671341fa.9.1786986494173; Mon, 17 Aug 2026 10:08:14 -0700 (PDT) Received: from yantra.. (dsl-trebng21-58c187-236.dhcp.inet.fi. [88.193.135.236]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-3a16b0e54casm6053841fa.15.2026.08.17.10.08.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Aug 2026 10:08:13 -0700 (PDT) From: Rupesh Majhi To: Andy Shevchenko , David Lechner , Eddie James , Joel Stanley , Jonathan Cameron , =?UTF-8?q?Nuno=20S=C3=A1?= Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Rupesh Majhi Subject: [PATCH v5 2/3] iio: pressure: dps310: add triggered buffer support Date: Mon, 17 Aug 2026 20:07:24 +0300 Message-ID: <20260817170725.1074078-3-zoone.rupert@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260817170725.1074078-1-zoone.rupert@gmail.com> References: <20260817170725.1074078-1-zoone.rupert@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add triggered buffer support so pressure and temperature can be captured into a buffer instead of only through one-shot sysfs reads. The device measures continuously in background mode, so a capture is just a read of the latest results and no buffer setup ops are needed. Pressure has to be computed from the raw register value with the compensation polynomial in section 4.9.1 of the datasheet, which also needs a temperature reading. To keep full resolution in the buffer without disagreeing with the unit the existing processed attribute reports, add raw and scale attributes for pressure, raw in Pa and scale 1/1000 to convert to kPa. The channel definition carries a comment explaining why it is done this way here and why it should not be copied into other drivers. Temperature is already a full resolution value in its base unit of millidegrees Celsius, so it stays a processed channel. Either channel can be enabled on its own. Temperature is always sampled because the pressure compensation needs it, but only the enabled channels are pushed to the buffer. The raw read helpers are split into variants that expect the lock to be held, so the trigger handler takes the lock once per scan instead of once per value. That also lets dps310_calculate_pressure() drop its mutex_trylock() dance, as the temperature refresh now always happens under the caller's lock instead of only when the lock happened to be free. Sysfs sample reads and reconfiguration return -EBUSY while the buffer is enabled, since they share the capture path's values and configuration. Signed-off-by: Rupesh Majhi --- drivers/iio/pressure/Kconfig | 2 + drivers/iio/pressure/dps310.c | 305 ++++++++++++++++++++++++++-------- 2 files changed, 242 insertions(+), 65 deletions(-) diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 838a8340c4c0..cef8b90b9ae7 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -112,6 +112,8 @@ config DPS310 tristate "Infineon DPS310 pressure and temperature sensor" depends on I2C select REGMAP_I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Support for the Infineon DPS310 digital barometric pressure sensor. It can be accessed over I2C bus. diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 68382960382f..0d6e65766469 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -20,8 +20,11 @@ #include #include =20 +#include #include #include +#include +#include =20 #define DPS310_DEV_NAME "dps310" =20 @@ -92,19 +95,56 @@ struct dps310_data { bool timeout_recovery_failed; }; =20 +enum dps310_scan_index { + DPS310_SCAN_TEMP, + DPS310_SCAN_PRESSURE, +}; + static const struct iio_chan_spec dps310_channels[] =3D { { .type =3D IIO_TEMP, .info_mask_separate =3D BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index =3D DPS310_SCAN_TEMP, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_CPU, + }, }, { .type =3D IIO_PRESSURE, + /* + * Pressure is only meaningful once the raw register value has + * been run through the compensation polynomial in section 4.9.1 + * of the datasheet, which needs a temperature reading as well. + * So what is reported as _raw here is already compensated, in + * Pa, and _scale converts it to the kPa the ABI asks for. The + * _processed attribute reports the same value and predates + * buffer support, so it has to stay. + * + * Please do not copy this pattern into other drivers. A raw + * attribute that is not the raw register value is only + * tolerable here because the alternative is either losing + * resolution in the buffer or breaking existing users of + * _processed. + */ .info_mask_separate =3D BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_PROCESSED), + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index =3D DPS310_SCAN_PRESSURE, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_CPU, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; =20 /* To be called after checking the COEF_RDY bit in MEAS_CFG */ @@ -463,7 +503,8 @@ static int dps310_ready(struct dps310_data *data, int r= eady_bit, int timeout) return 0; } =20 -static int dps310_read_pres_raw(struct dps310_data *data) +/* Called with lock held */ +static int dps310_read_pres_raw_locked(struct dps310_data *data) { int rc; int rate; @@ -471,30 +512,25 @@ static int dps310_read_pres_raw(struct dps310_data *d= ata) s32 raw; u8 val[3]; =20 - if (mutex_lock_interruptible(&data->lock)) - return -EINTR; - rc =3D dps310_get_pres_samp_freq(data, &rate); if (rc) - goto done; + return rc; =20 timeout =3D DPS310_POLL_TIMEOUT_US(rate); =20 /* Poll for sensor readiness; base the timeout upon the sample rate. */ rc =3D dps310_ready(data, DPS310_PRS_RDY, timeout); if (rc) - goto done; + return rc; =20 rc =3D regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val)); if (rc < 0) - goto done; + return rc; =20 raw =3D (val[0] << 16) | (val[1] << 8) | val[2]; data->pressure_raw =3D sign_extend32(raw, 23); =20 -done: - mutex_unlock(&data->lock); - return rc; + return 0; } =20 /* Called with lock held */ @@ -514,31 +550,45 @@ static int dps310_read_temp_ready(struct dps310_data = *data) return 0; } =20 -static int dps310_read_temp_raw(struct dps310_data *data) +/* Called with lock held */ +static int dps310_read_temp_raw_locked(struct dps310_data *data) { int rc; int rate; int timeout; =20 - if (mutex_lock_interruptible(&data->lock)) - return -EINTR; - rc =3D dps310_get_temp_samp_freq(data, &rate); if (rc) - goto done; + return rc; =20 timeout =3D DPS310_POLL_TIMEOUT_US(rate); =20 /* Poll for sensor readiness; base the timeout upon the sample rate. */ rc =3D dps310_ready(data, DPS310_TMP_RDY, timeout); if (rc) - goto done; + return rc; =20 - rc =3D dps310_read_temp_ready(data); + return dps310_read_temp_ready(data); +} =20 -done: - mutex_unlock(&data->lock); - return rc; +/* + * Refresh the cached temperature if a new measurement is ready, so that t= he + * pressure compensation below uses a recent value. Errors are not fatal h= ere, + * the previous temperature is used instead. + * + * Called with lock held. + */ +static void dps310_refresh_temp_locked(struct dps310_data *data) +{ + int rc; + int t_ready; + + rc =3D regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready); + if (rc) + return; + + if (t_ready & DPS310_TMP_RDY) + dps310_read_temp_ready(data); } =20 static bool dps310_is_writeable_reg(struct device *dev, unsigned int reg) @@ -580,59 +630,52 @@ static int dps310_write_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int rc; struct dps310_data *data =3D iio_priv(iio); =20 - if (mutex_lock_interruptible(&data->lock)) + /* Reconfiguring mid-capture would change the values being captured */ + IIO_DEV_ACQUIRE_DIRECT_MODE(iio, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ACQUIRE(mutex_intr, lock)(&data->lock); + if (ACQUIRE_ERR(mutex_intr, &lock)) return -EINTR; =20 switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: switch (chan->type) { case IIO_PRESSURE: - rc =3D dps310_set_pres_samp_freq(data, val); - break; + return dps310_set_pres_samp_freq(data, val); =20 case IIO_TEMP: - rc =3D dps310_set_temp_samp_freq(data, val); - break; + return dps310_set_temp_samp_freq(data, val); =20 default: - rc =3D -EINVAL; - break; + return -EINVAL; } - break; =20 case IIO_CHAN_INFO_OVERSAMPLING_RATIO: switch (chan->type) { case IIO_PRESSURE: - rc =3D dps310_set_pres_precision(data, val); - break; + return dps310_set_pres_precision(data, val); =20 case IIO_TEMP: - rc =3D dps310_set_temp_precision(data, val); - break; + return dps310_set_temp_precision(data, val); =20 default: - rc =3D -EINVAL; - break; + return -EINVAL; } - break; =20 default: - rc =3D -EINVAL; - break; + return -EINVAL; } - - mutex_unlock(&data->lock); - return rc; } =20 +/* Called with lock held */ static int dps310_calculate_pressure(struct dps310_data *data, int *val) { int i; int rc; - int t_ready; int kpi; int kti; s64 rem =3D 0ULL; @@ -656,15 +699,6 @@ static int dps310_calculate_pressure(struct dps310_dat= a *data, int *val) kp =3D (s64)kpi; kt =3D (s64)kti; =20 - /* Refresh temp if it's ready, otherwise just use the latest value */ - if (mutex_trylock(&data->lock)) { - rc =3D regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready); - if (rc >=3D 0 && t_ready & DPS310_TMP_RDY) - dps310_read_temp_ready(data); - - mutex_unlock(&data->lock); - } - p =3D (s64)data->pressure_raw; t =3D (s64)data->temp_raw; =20 @@ -710,6 +744,28 @@ static int dps310_calculate_pressure(struct dps310_dat= a *data, int *val) return 0; } =20 +/* + * Sample the pressure and compensate it. Shared by the raw and processed + * attributes, which report the same value in different units, and takes t= he + * lock once for the whole sequence. + */ +static int dps310_read_pressure_value(struct dps310_data *data, int *val) +{ + int rc; + + ACQUIRE(mutex_intr, lock)(&data->lock); + if (ACQUIRE_ERR(mutex_intr, &lock)) + return -EINTR; + + rc =3D dps310_read_pres_raw_locked(data); + if (rc) + return rc; + + dps310_refresh_temp_locked(data); + + return dps310_calculate_pressure(data, val); +} + static int dps310_read_pressure(struct dps310_data *data, int *val, int *v= al2, long mask) { @@ -723,18 +779,27 @@ static int dps310_read_pressure(struct dps310_data *d= ata, int *val, int *val2, =20 return IIO_VAL_INT; =20 - case IIO_CHAN_INFO_PROCESSED: - rc =3D dps310_read_pres_raw(data); + case IIO_CHAN_INFO_RAW: + rc =3D dps310_read_pressure_value(data, val); if (rc) return rc; =20 - rc =3D dps310_calculate_pressure(data, val); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_PROCESSED: + rc =3D dps310_read_pressure_value(data, val); if (rc) return rc; =20 *val2 =3D 1000; /* Convert Pa to KPa per IIO ABI */ return IIO_VAL_FRACTIONAL; =20 + case IIO_CHAN_INFO_SCALE: + /* The raw value is in Pa, the ABI wants kPa */ + *val =3D 1; + *val2 =3D 1000; + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: rc =3D dps310_get_pres_precision(data, val); if (rc) @@ -768,6 +833,21 @@ static int dps310_calculate_temp(struct dps310_data *d= ata, int *val) return 0; } =20 +static int dps310_read_temp_value(struct dps310_data *data, int *val) +{ + int rc; + + ACQUIRE(mutex_intr, lock)(&data->lock); + if (ACQUIRE_ERR(mutex_intr, &lock)) + return -EINTR; + + rc =3D dps310_read_temp_raw_locked(data); + if (rc) + return rc; + + return dps310_calculate_temp(data, val); +} + static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, long mask) { @@ -782,11 +862,7 @@ static int dps310_read_temp(struct dps310_data *data, = int *val, int *val2, return IIO_VAL_INT; =20 case IIO_CHAN_INFO_PROCESSED: - rc =3D dps310_read_temp_raw(data); - if (rc) - return rc; - - rc =3D dps310_calculate_temp(data, val); + rc =3D dps310_read_temp_value(data, val); if (rc) return rc; =20 @@ -804,12 +880,10 @@ static int dps310_read_temp(struct dps310_data *data,= int *val, int *val2, } } =20 -static int dps310_read_raw(struct iio_dev *iio, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) +static int dps310_read_channel(struct dps310_data *data, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { - struct dps310_data *data =3D iio_priv(iio); - switch (chan->type) { case IIO_PRESSURE: return dps310_read_pressure(data, val, val2, mask); @@ -822,6 +896,97 @@ static int dps310_read_raw(struct iio_dev *iio, } } =20 +static int dps310_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct dps310_data *data =3D iio_priv(iio); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: { + /* + * Sampling here consumes the same measurement the capture path + * reads, so refuse while the buffer is enabled. + */ + IIO_DEV_ACQUIRE_DIRECT_MODE(iio, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + return dps310_read_channel(data, chan, val, val2, mask); + } + default: + return dps310_read_channel(data, chan, val, val2, mask); + } +} + +/* Called with lock held */ +static int dps310_fill_scan(struct iio_dev *iio, u8 *buffer) +{ + struct dps310_data *data =3D iio_priv(iio); + int rc; + int pos =3D 0; + s32 value; + + /* + * The pressure compensation needs a temperature reading, so temperature + * is sampled even when only the pressure channel is enabled. + */ + rc =3D dps310_read_temp_raw_locked(data); + if (rc) + return rc; + + if (test_bit(DPS310_SCAN_TEMP, iio->active_scan_mask)) { + rc =3D dps310_calculate_temp(data, &value); + if (rc) + return rc; + + /* Millidegrees Celsius */ + memcpy(&buffer[pos], &value, sizeof(value)); + pos +=3D sizeof(value); + } + + if (test_bit(DPS310_SCAN_PRESSURE, iio->active_scan_mask)) { + rc =3D dps310_read_pres_raw_locked(data); + if (rc) + return rc; + + rc =3D dps310_calculate_pressure(data, &value); + if (rc) + return rc; + + /* Pascals, see the comment on the channel definition */ + memcpy(&buffer[pos], &value, sizeof(value)); + } + + return 0; +} + +static irqreturn_t dps310_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf =3D p; + struct iio_dev *iio =3D pf->indio_dev; + struct dps310_data *data =3D iio_priv(iio); + /* + * Either channel can be enabled on its own, so the offset of the second + * value depends on the scan mask and the layout cannot be described + * with a structure. Sized for both 32-bit channels plus the timestamp. + */ + u8 buffer[16] __aligned(8) =3D { }; + int rc =3D 0; + + scoped_guard(mutex, &data->lock) + rc =3D dps310_fill_scan(iio, buffer); + + if (!rc) + iio_push_to_buffers_with_ts(iio, buffer, sizeof(buffer), + pf->timestamp); + + iio_trigger_notify_done(iio->trig); + + return IRQ_HANDLED; +} + static void dps310_reset(void *action_data) { struct dps310_data *data =3D action_data; @@ -877,6 +1042,16 @@ static int dps310_probe(struct i2c_client *client) if (rc) return rc; =20 + /* + * The device measures continuously in background mode, so a capture is + * just a read of the latest results and no buffer setup ops are needed. + */ + rc =3D devm_iio_triggered_buffer_setup(&client->dev, iio, + iio_pollfunc_store_time, + dps310_trigger_handler, NULL); + if (rc) + return rc; + rc =3D devm_iio_device_register(&client->dev, iio); if (rc) return rc; --=20 2.43.0 From nobody Mon Sep 28 21:03:43 2026 Received: from mail-lj1-f179.google.com (mail-lj1-f179.google.com [209.85.208.179]) (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 3A8094657E5 for ; Mon, 17 Aug 2026 17:08:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786986500; cv=none; b=fu2fte+UlkhGcq8ZXT98nVN5POjY4LXFKTZCNoK0YRFFL4lvBQYJQ14es0jFXDqx5qrf2Gf4Q6jgOVXcPmt+/tQ2jOr8LcySNgL2BJIfRUuohFxJGGYf/zGFPNvx8wf+G5+kzA0gmLrzJlpSAh8v0q5zUehCpycYP8/Qs0Onl9E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786986500; c=relaxed/simple; bh=N1xD8krKnHK5na4SLrnNTQwU9ig0FMp7wmdvaxTlqQI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Lyj/xXOxkCWVfBERy7Bxlscv8JiCFuxj60YCCRUvn+hfxn2x4ODQGscD8H2+PgK70nwTXE7jtZii/2qvcA1QfD5hwm/Kqcs+4wCUPIkl1fJgUKEbQp5kX0taOsaWE63QIm9LLnnZTL0T5SK5jc+tfOguSH11tp/d+v1D+Qskrhw= 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=f+Jc/Rqe; arc=none smtp.client-ip=209.85.208.179 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="f+Jc/Rqe" Received: by mail-lj1-f179.google.com with SMTP id 38308e7fff4ca-39c94fccf3eso33163611fa.0 for ; Mon, 17 Aug 2026 10:08:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786986496; x=1787591296; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=UHsObEtbSuRZN9bKJ22xjd0JtKFsDuiOyCfU/kVCApU=; b=f+Jc/Rqew71DqTFIUQbMI+ZoOXLsqKlQata+c8gbYRI8zFjCGgTLO7k5qCQAgz1gEN bERevJX62Ac8J6shgTpYoLa6bTOFhYCAWOX+go1LLVVPFURKTkMyuFQ7w74jVVxyuqke 4/EZrX/Qu32xjIyA0Zot89WpgzsH6Xcfc+wUPyLeCgHH99w/iUWCOtacT+HRgdtnIsoN LEDhDQdM8QWsffPD+baKgvM+0SDUk7rwmBEM/REoO4KeGMqfXDThoTq8ryBE0EcRFakB AOHy1tmgQTutZl44JUUYOypB0pwGasGlW20mJDIyXubQPd3nF6WnB5Hfly579eJ8PWNY xdUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786986496; x=1787591296; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=UHsObEtbSuRZN9bKJ22xjd0JtKFsDuiOyCfU/kVCApU=; b=SX6f6JoAE1CprvKzJEKY1a8UiwZJry+60sWHAcD9QSur9T/3mmKZ5102TcJ1ACEqrS u17DYZsPExmfqjnXlWJeIknpKC8dJI9f0pBjB9mSERhULSkn4oyBCqMNASBUvCvni2Ac jX6mCqqDdDWH0CNzGl8WCnKk99vVFCZQ2jW/fHLJp+bcMRjVtd3O7GkuYpmNbipo291V 1uD2yrzaJZwMAJPnWySWRt3BGxQ0l34GvtHUE4hwEuCiwr2uQf0u8CV3JHprFhEhLNQ5 8ZDIeqxRgWwDGaZJ060bnKNaYDd4LBk+vfDqNZOjBudkSuSzj6NuywTUu+lmIhxbo9G1 3vGQ== X-Forwarded-Encrypted: i=1; AHgh+RpmWOsuY/fRrDt6nI9fS8POehEl/cvKaPtF6usi2GF4hXpvkRqe6kSq6JLF8rrMBlMlC2c8xnuS4OkaZgc=@vger.kernel.org X-Gm-Message-State: AOJu0Ywv2BrO8zvQPezz7MO7co5dojSWTIITc4VXINbXlIURMtIwrv8/ tg+ROB63A5CKDmnZOS91SvDpsGNqh7Q/NT4OeZBPlE1wqTMd1uj3Eb6Q X-Gm-Gg: AR+sD10cABqTSjX0IYRaU1dQg+XiEi/p0CInHF0LV4s+65V9wjWsei/MyEFOlDckLUi mTr6oP5oJoFiCrGSOVDxDaFDCg/dHDHjXv+MV8yVbPlGk4IVWoHn2UzzwqJTLRnfKfDiRV1ypYu 1FNKaV7s3ormy9bse10PJrfZNSia7DPBxqsrEMdOxBUveNE3YKdrwpy4EFnSnywHq40O47wF7jS Liexy5X+5Ah8rd/jkEAyhZMnperQosw9SfHdOUZj4nPf79hZ5WsUpXnDpcrV1zgsSI7T2vN5LZ/ q4JAHpKlUW0xWbWXP4z+2tPPPk/xeztBxBIN2z8oF0WMkjeAIxcyKcEhPMII1qQYQD/LTUo/BR1 og0NzNfqWcCvbTr7wbWRrHQFADZ99KtyF/T3a/X5lIaWCObX2KbNMs6imsvV6W1sepFC2bL/Yq7 DRiX6+4oGAQL82hk+3qu6cOOy9kyyHcEaOP3anb6ncxfd2pVY0xYjVj8yG6sc1r28DdDhQn65b2 X5EnpH4qLSuxXJx/MrXSyEttoTMf1giumunSttOzWYw9DiO6KnsjolkbDU= X-Received: by 2002:a2e:bea5:0:b0:39c:6d3a:2dd7 with SMTP id 38308e7fff4ca-3a1324b3f12mr27243991fa.17.1786986495816; Mon, 17 Aug 2026 10:08:15 -0700 (PDT) Received: from yantra.. (dsl-trebng21-58c187-236.dhcp.inet.fi. [88.193.135.236]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-3a16b0e54casm6053841fa.15.2026.08.17.10.08.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Aug 2026 10:08:15 -0700 (PDT) From: Rupesh Majhi To: Andy Shevchenko , David Lechner , Eddie James , Joel Stanley , Jonathan Cameron , =?UTF-8?q?Nuno=20S=C3=A1?= Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Rupesh Majhi Subject: [PATCH v5 3/3] iio: pressure: dps310: add hardware FIFO support Date: Mon, 17 Aug 2026 20:07:25 +0300 Message-ID: <20260817170725.1074078-4-zoone.rupert@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260817170725.1074078-1-zoone.rupert@gmail.com> References: <20260817170725.1074078-1-zoone.rupert@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 DPS310 has a 32 entry FIFO, shared between the pressure and temperature streams, which the driver has never used. Enable it for buffered capture so a reader is woken once per batch of samples rather than once per sample. The FIFO is used when no external trigger is attached, and left disabled in favor of the trigger when one is. That selection needs no policy of its own: iio_verify_update() already picks INDIO_BUFFER_TRIGGERED when a trigger is present and INDIO_BUFFER_SOFTWARE when it is not, so both modes are advertised and the buffer setup ops branch on iio_device_get_current_mode(). This follows drivers/iio/pressure/rohm-bm1390.c. The drain is timer driven rather than interrupt driven. The binding has no interrupts property and no in-tree device tree wires the INT pin, so there is no interrupt to use. hwfifo_flush_to_buffer alone is not enough either: iio_buffer_read() sleeps on rb->pollq with no timeout and only a push wakes it, so a blocking reader would hang with samples sitting in the hardware. The flush hook is still provided so poll() and non-blocking readers can pull early. It stops at the read rather than after it when the caller limits the count, because entries leave the hardware as they are read and any collected past the limit would have to be discarded. Because the hardware stops recording when the FIFO is full instead of overwriting, a late drain loses the newest samples rather than the oldest, so the interval is kept below half the time the FIFO takes to fill. The DPS310 has no configurable hardware watermark, only a FIFO-full condition, so the value passed to hwfifo_set_watermark() is taken as the number of scans the user is prepared to wait for and bounds the interval from the other side. Entries carry no timestamps. They are synthesised by working back from the drain at the configured sample period, anchored so that a batch never starts before the previous one ended. Where a drain collected more than the configured rate accounts for, the batch is spread across the window instead so the timestamps stay monotonic. These are estimates, not hardware timestamps. Every entry is read through the pressure registers whichever measurement produced it, with the type tagged in the LSB and 0x800000 returned once the FIFO is empty. Pressure entries drive the scans and reuse the most recent temperature entry for compensation, which keeps the two configured rates independent; pressure entries arriving before any temperature cannot be compensated and are dropped. With only the temperature channel enabled there is nothing to pair with, so temperature drives the scans itself, and both the drain and the watermark-to-interval conversion follow whichever rate is driving. The file header still claimed only a single temperature read was supported, which this patch is the last word against, so it goes too. Signed-off-by: Rupesh Majhi --- drivers/iio/pressure/dps310.c | 413 +++++++++++++++++++++++++++++++++- 1 file changed, 404 insertions(+), 9 deletions(-) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 0d6e65766469..0a93c64d6db5 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -2,16 +2,11 @@ // Copyright IBM Corp 2019 /* * The DPS310 is a barometric pressure and temperature sensor. - * Currently only reading a single temperature is supported by - * this driver. * * https://www.infineon.com/dgdl/?fileId=3D5546d462576f34750157750826c42242 * * Temperature calculation: * c0 * 0.5 + c1 * T_raw / kT =C2=B0C - * - * TODO: - * - Optionally support the FIFO */ =20 #include @@ -19,6 +14,8 @@ #include #include #include +#include +#include =20 #include #include @@ -57,9 +54,31 @@ #define DPS310_FIFO_EN BIT(1) #define DPS310_SPI_EN BIT(0) #define DPS310_RESET 0x0c +#define DPS310_FIFO_FLUSH BIT(7) #define DPS310_RESET_MAGIC 0x09 #define DPS310_COEF_BASE 0x10 =20 +/* + * Section 4.8: the FIFO holds 32 entries shared between the pressure and + * temperature streams, and stops recording once full rather than overwrit= ing. + * A late drain therefore loses the newest samples, not the oldest. + */ +#define DPS310_FIFO_DEPTH 32 + +/* Read back in place of a sample once the FIFO has been drained */ +#define DPS310_FIFO_EMPTY_VAL 0x800000 + +/* The LSB of a FIFO entry tags which measurement produced it */ +#define DPS310_FIFO_TAG_PRS BIT(0) + +/* + * Bounds on the drain interval. The lower bound keeps a fast rate from + * flooding the workqueue; the upper bound keeps the FIFO from filling whi= le + * nothing is looking at it. + */ +#define DPS310_DRAIN_MIN_MS 20 +#define DPS310_DRAIN_MAX_MS 2000 + /* Make sure sleep time is <=3D 30ms for usleep_range */ #define DPS310_POLL_SLEEP_US(t) min(30000, (t) / 8) /* Silently handle error in rate value here */ @@ -93,6 +112,15 @@ struct dps310_data { s32 pressure_raw; s32 temp_raw; bool timeout_recovery_failed; + + /* FIFO capture state, used only while the hardware FIFO is enabled */ + struct iio_dev *iio; + struct delayed_work fifo_work; + unsigned int watermark; + unsigned int drain_interval_ms; + s64 fifo_timestamp; + s32 fifo_temp_raw; + bool fifo_temp_valid; }; =20 enum dps310_scan_index { @@ -962,6 +990,344 @@ static int dps310_fill_scan(struct iio_dev *iio, u8 *= buffer) return 0; } =20 +/* Called with lock held */ +static int dps310_fifo_hw_flush(struct dps310_data *data) +{ + return regmap_write(data->regmap, DPS310_RESET, DPS310_FIFO_FLUSH); +} + +/* Called with lock held */ +static int dps310_fifo_set_enable(struct dps310_data *data, bool enable) +{ + return regmap_write_bits(data->regmap, DPS310_CFG_REG, DPS310_FIFO_EN, + enable ? DPS310_FIFO_EN : 0); +} + +/* + * There is no interrupt wired on any in-tree platform and the binding has= no + * interrupts property, so the FIFO is drained on a timer. The interval ha= s to + * stay below the time the FIFO takes to fill, because the hardware stops + * recording when full instead of overwriting: draining late loses the new= est + * samples rather than the oldest. + * + * Called with lock held. + */ +static int dps310_fifo_interval(struct dps310_data *data, unsigned int *ms) +{ + bool pressure_enabled =3D test_bit(DPS310_SCAN_PRESSURE, + data->iio->active_scan_mask); + unsigned int fill_ms, want_ms; + int rc, prs_rate, tmp_rate; + + rc =3D dps310_get_pres_samp_freq(data, &prs_rate); + if (rc) + return rc; + + rc =3D dps310_get_temp_samp_freq(data, &tmp_rate); + if (rc) + return rc; + + /* Both streams share the same entries, so they fill it together. */ + fill_ms =3D MSEC_PER_SEC * DPS310_FIFO_DEPTH / (prs_rate + tmp_rate); + + /* + * The DPS310 has no configurable hardware watermark, only a FIFO-full + * condition, so the watermark is taken as the number of scans the user + * is prepared to wait for and drives the drain interval instead. Scans + * come at the rate of whichever measurement drives them, which is not + * the pressure rate when only the temperature channel is enabled. + */ + want_ms =3D data->watermark * MSEC_PER_SEC / + (pressure_enabled ? prs_rate : tmp_rate); + + *ms =3D clamp_t(unsigned int, min(want_ms, fill_ms / 2), + DPS310_DRAIN_MIN_MS, DPS310_DRAIN_MAX_MS); + + return 0; +} + +/* + * Read a single FIFO entry. Returns 1 if a sample was read, 0 once the FI= FO is + * empty, or a negative error. Called with lock held. + */ +static int dps310_fifo_read_entry(struct dps310_data *data, s32 *value, + bool *is_pressure) +{ + u8 val[3]; + s32 raw; + int rc; + + /* + * Every entry is read through the pressure registers regardless of + * which measurement produced it, with the type tagged in the LSB. + */ + rc =3D regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val)); + if (rc < 0) + return rc; + + raw =3D (val[0] << 16) | (val[1] << 8) | val[2]; + if (raw =3D=3D DPS310_FIFO_EMPTY_VAL) + return 0; + + *is_pressure =3D raw & DPS310_FIFO_TAG_PRS; + *value =3D sign_extend32(raw, 23); + + return 1; +} + +/* Called with lock held */ +static int dps310_fifo_push_scan(struct dps310_data *data, s32 temp_raw, + s32 pressure_raw, s64 timestamp) +{ + struct iio_dev *iio =3D data->iio; + u8 buffer[16] __aligned(8) =3D { }; + int pos =3D 0, rc; + s32 value; + + /* + * The compensation helpers read the cached raw values. Sysfs reads take + * the direct-mode claim, so they cannot be looking at these while a + * buffered capture is running. + */ + data->temp_raw =3D temp_raw; + data->pressure_raw =3D pressure_raw; + + if (test_bit(DPS310_SCAN_TEMP, iio->active_scan_mask)) { + rc =3D dps310_calculate_temp(data, &value); + if (rc) + return rc; + + memcpy(&buffer[pos], &value, sizeof(value)); + pos +=3D sizeof(value); + } + + if (test_bit(DPS310_SCAN_PRESSURE, iio->active_scan_mask)) { + rc =3D dps310_calculate_pressure(data, &value); + if (rc) + return rc; + + memcpy(&buffer[pos], &value, sizeof(value)); + } + + iio_push_to_buffers_with_ts(iio, buffer, sizeof(buffer), timestamp); + + return 0; +} + +/* + * Drain the FIFO and push the samples it held, stopping once max_scans sc= ans + * are in hand or draining everything when max_scans is zero. Stopping at = the + * read rather than after it matters: entries leave the hardware as they a= re + * read, so any collected beyond the caller's limit would have to be disca= rded. + * + * Returns the number of scans pushed. Called with lock held. + */ +static int dps310_fifo_drain(struct dps310_data *data, s64 now, + unsigned int max_scans) +{ + bool pressure_enabled =3D test_bit(DPS310_SCAN_PRESSURE, + data->iio->active_scan_mask); + bool temp_valid =3D data->fifo_temp_valid; + bool is_pressure[DPS310_FIFO_DEPTH]; + s32 raw[DPS310_FIFO_DEPTH]; + unsigned int i, n =3D 0, scans =3D 0, pushed =3D 0; + s64 interval, first; + int rc, rate; + + /* + * Empty the hardware first and compensate afterwards, so the time spent + * in the polynomial is not time the FIFO spends filling. + * + * Pressure entries drive the scans and reuse the most recent + * temperature, so the two rates stay independent; entries arriving + * before any temperature cannot be compensated and are dropped. With + * only the temperature channel enabled there is nothing to pair with + * and temperature drives the scans itself. + */ + for (i =3D 0; i < DPS310_FIFO_DEPTH; i++) { + rc =3D dps310_fifo_read_entry(data, &raw[n], &is_pressure[n]); + if (rc < 0) + return rc; + if (!rc) + break; + + if (!is_pressure[n]) { + temp_valid =3D true; + if (!pressure_enabled) + scans++; + } else if (pressure_enabled && temp_valid) { + scans++; + } + n++; + + if (max_scans && scans >=3D max_scans) + break; + } + + if (!scans) + return 0; + + /* + * FIFO entries carry no timestamps. They are synthesised by working + * back from the drain with the configured period of whichever + * measurement drives the scans, so the spacing matches the sampling + * frequency the user asked for instead of varying with how much each + * drain happened to collect. These are estimates, not hardware + * timestamps. + */ + rc =3D pressure_enabled ? dps310_get_pres_samp_freq(data, &rate) : + dps310_get_temp_samp_freq(data, &rate); + if (rc) + return rc; + + interval =3D div_s64(NSEC_PER_SEC, rate); + first =3D now - (s64)(scans - 1) * interval; + + /* + * A batch must not start before the previous one ended, or the buffer + * would carry timestamps that go backwards. If this drain collected + * more than the configured rate accounts for, spread it across the + * window since the last sample instead. + */ + if (data->fifo_timestamp && first <=3D data->fifo_timestamp) { + interval =3D max_t(s64, div_s64(now - data->fifo_timestamp, scans), 1); + first =3D data->fifo_timestamp + interval; + } + + for (i =3D 0; i < n; i++) { + s64 timestamp; + + if (!is_pressure[i]) { + data->fifo_temp_raw =3D raw[i]; + data->fifo_temp_valid =3D true; + + if (pressure_enabled) + continue; + } else if (!pressure_enabled || !data->fifo_temp_valid) { + continue; + } + + timestamp =3D first + (s64)pushed * interval; + + rc =3D dps310_fifo_push_scan(data, + is_pressure[i] ? data->fifo_temp_raw + : raw[i], + is_pressure[i] ? raw[i] : 0, + timestamp); + if (rc) + return rc; + + data->fifo_timestamp =3D timestamp; + pushed++; + } + + return pushed; +} + +static void dps310_fifo_work(struct work_struct *work) +{ + struct dps310_data *data =3D container_of(to_delayed_work(work), + struct dps310_data, fifo_work); + int rc; + + scoped_guard(mutex, &data->lock) + rc =3D dps310_fifo_drain(data, iio_get_time_ns(data->iio), 0); + + if (rc < 0) + dev_dbg(&data->client->dev, "FIFO drain failed: %d\n", rc); + + schedule_delayed_work(&data->fifo_work, + msecs_to_jiffies(data->drain_interval_ms)); +} + +static int dps310_hwfifo_set_watermark(struct iio_dev *iio, unsigned int v= al) +{ + struct dps310_data *data =3D iio_priv(iio); + + data->watermark =3D clamp_t(unsigned int, val, 1, DPS310_FIFO_DEPTH); + + return 0; +} + +static int dps310_hwfifo_flush(struct iio_dev *iio, unsigned int count) +{ + struct dps310_data *data =3D iio_priv(iio); + int rc; + + /* + * With a trigger attached the FIFO is left disabled, and the pressure + * registers then hold the latest measurement rather than queued entries + * with an empty marker to stop on. There is nothing to drain. + */ + if (iio_device_get_current_mode(iio) !=3D INDIO_BUFFER_SOFTWARE) + return 0; + + scoped_guard(mutex, &data->lock) + rc =3D dps310_fifo_drain(data, iio_get_time_ns(iio), count); + + return rc; +} + +static int dps310_buffer_postenable(struct iio_dev *iio) +{ + struct dps310_data *data =3D iio_priv(iio); + int rc; + + /* + * An attached trigger drives the capture instead, so the FIFO stays + * disabled and the two never both feed the buffer. + */ + if (iio_device_get_current_mode(iio) =3D=3D INDIO_BUFFER_TRIGGERED) + return 0; + + guard(mutex)(&data->lock); + + data->fifo_temp_valid =3D false; + data->fifo_timestamp =3D 0; + + rc =3D dps310_fifo_interval(data, &data->drain_interval_ms); + if (rc) + return rc; + + /* Drop whatever accumulated before the buffer was enabled */ + rc =3D dps310_fifo_hw_flush(data); + if (rc) + return rc; + + rc =3D dps310_fifo_set_enable(data, true); + if (rc) + return rc; + + schedule_delayed_work(&data->fifo_work, + msecs_to_jiffies(data->drain_interval_ms)); + + return 0; +} + +static int dps310_buffer_predisable(struct iio_dev *iio) +{ + struct dps310_data *data =3D iio_priv(iio); + int rc; + + if (iio_device_get_current_mode(iio) =3D=3D INDIO_BUFFER_TRIGGERED) + return 0; + + cancel_delayed_work_sync(&data->fifo_work); + + guard(mutex)(&data->lock); + + rc =3D dps310_fifo_set_enable(data, false); + if (rc) + return rc; + + return dps310_fifo_hw_flush(data); +} + +static const struct iio_buffer_setup_ops dps310_buffer_setup_ops =3D { + .postenable =3D dps310_buffer_postenable, + .predisable =3D dps310_buffer_predisable, +}; + static irqreturn_t dps310_trigger_handler(int irq, void *p) { struct iio_poll_func *pf =3D p; @@ -994,6 +1360,17 @@ static void dps310_reset(void *action_data) dps310_reset_wait(data); } =20 +/* + * The drain reschedules itself, so make sure it is stopped before the dev= ice + * goes away even if the buffer was never disabled cleanly. + */ +static void dps310_cancel_fifo_work(void *action_data) +{ + struct dps310_data *data =3D action_data; + + cancel_delayed_work_sync(&data->fifo_work); +} + static const struct regmap_config dps310_regmap_config =3D { .reg_bits =3D 8, .val_bits =3D 8, @@ -1006,6 +1383,8 @@ static const struct regmap_config dps310_regmap_confi= g =3D { static const struct iio_info dps310_info =3D { .read_raw =3D dps310_read_raw, .write_raw =3D dps310_write_raw, + .hwfifo_set_watermark =3D dps310_hwfifo_set_watermark, + .hwfifo_flush_to_buffer =3D dps310_hwfifo_flush, }; =20 static int dps310_probe(struct i2c_client *client) @@ -1021,13 +1400,22 @@ static int dps310_probe(struct i2c_client *client) =20 data =3D iio_priv(iio); data->client =3D client; + data->iio =3D iio; + data->watermark =3D 1; mutex_init(&data->lock); + INIT_DELAYED_WORK(&data->fifo_work, dps310_fifo_work); =20 iio->name =3D id->name; iio->channels =3D dps310_channels; iio->num_channels =3D ARRAY_SIZE(dps310_channels); iio->info =3D &dps310_info; - iio->modes =3D INDIO_DIRECT_MODE; + /* + * Both buffer modes are advertised so that iio_verify_update() picks + * INDIO_BUFFER_TRIGGERED when a trigger is attached and falls back to + * INDIO_BUFFER_SOFTWARE, which the FIFO path uses, when one is not. + */ + iio->modes =3D INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED | + INDIO_BUFFER_SOFTWARE; =20 data->regmap =3D devm_regmap_init_i2c(client, &dps310_regmap_config); if (IS_ERR(data->regmap)) @@ -1043,12 +1431,19 @@ static int dps310_probe(struct i2c_client *client) return rc; =20 /* - * The device measures continuously in background mode, so a capture is - * just a read of the latest results and no buffer setup ops are needed. + * The device measures continuously in background mode, so a triggered + * capture is just a read of the latest results. The setup ops start and + * stop the FIFO drain when no trigger is attached. */ rc =3D devm_iio_triggered_buffer_setup(&client->dev, iio, iio_pollfunc_store_time, - dps310_trigger_handler, NULL); + dps310_trigger_handler, + &dps310_buffer_setup_ops); + if (rc) + return rc; + + rc =3D devm_add_action_or_reset(&client->dev, dps310_cancel_fifo_work, + data); if (rc) return rc; =20 --=20 2.43.0