* [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver
@ 2026-06-28 19:13 Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device Jinseob Kim
` (6 more replies)
0 siblings, 7 replies; 16+ messages in thread
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Open Sensor Fusion (OSF) devices expose a UART/serdev host interface
for a sensor aggregation hub. This RFC adds a Linux IIO driver that
parses OSF frames and creates IIO devices at runtime from capability
reports provided by the device firmware.
When the corresponding capabilities are reported, the driver exposes
accelerometer, gyroscope, magnetometer, and temperature data as IIO
devices named osf-accel, osf-gyro, osf-magn, and osf-temp.
This remains RFC while the binding, protocol subset, runtime discovery
model, and driver-facing ABI are reviewed.
Changes in v6:
- Reworked the series as a 5-patch standalone RFC.
- Folded the previous transport and IIO registration split into one
final driver patch to avoid Kconfig and Makefile churn.
- Addressed binding feedback with generic host interface wording,
mandatory capability reporting, runtime discovery wording, no
Linux-specific binding language, and no fixed regulator provider in
the example.
- Added progressive MAINTAINERS coverage as files are introduced.
- Removed patch-split wording from Kconfig and introduced Kconfig and
Makefile entries in final form.
- Applied style cleanups including loop-local variables, unused include
cleanup, and a probe-local device pointer.
- Used designated initializers and guard/scoped_guard where useful.
- Kept the stream parser from discarding unauthenticated frame_len on
failed decode.
- Synchronized IIO buffer pushes with
iio_device_try_claim_buffer_mode() and release.
- Replaced iio_push_to_buffers_with_ts_unaligned() with local zeroed
scan storage and iio_push_to_buffers_with_ts().
Validation summary:
- git diff --check: pass.
- checkpatch --strict: pass, 0 errors, 0 warnings, 0 checks.
- dt_binding_check: pass with dtschema 2026.4.
- make KBUILD_MODPOST_WARN=1 W=1 M=drivers/iio/opensensorfusion:
pass, no compiler warnings.
- Local stream parser corruption/resync harness: pass.
- Static IIO scan layout and padding checks: pass.
- Raspberry Pi hardware/runtime smoke testing is pending for this v6
candidate.
Jinseob Kim (5):
dt-bindings: iio: add Open Sensor Fusion device
Documentation: iio: add Open Sensor Fusion driver overview
iio: osf: add protocol decoding
iio: osf: add authenticated stream parser
iio: osf: add UART IIO driver
.../bindings/iio/opensensorfusion,osf.yaml | 54 +++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
Documentation/iio/index.rst | 1 +
Documentation/iio/open-sensor-fusion.rst | 72 ++++
MAINTAINERS | 14 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/opensensorfusion/Kconfig | 16 +
drivers/iio/opensensorfusion/Makefile | 6 +
drivers/iio/opensensorfusion/osf_core.c | 291 +++++++++++++++++
drivers/iio/opensensorfusion/osf_core.h | 70 ++++
drivers/iio/opensensorfusion/osf_iio.c | 308 ++++++++++++++++++
drivers/iio/opensensorfusion/osf_iio.h | 22 ++
drivers/iio/opensensorfusion/osf_protocol.c | 258 +++++++++++++++
drivers/iio/opensensorfusion/osf_protocol.h | 97 ++++++
drivers/iio/opensensorfusion/osf_serdev.c | 114 +++++++
drivers/iio/opensensorfusion/osf_stream.c | 189 +++++++++++
drivers/iio/opensensorfusion/osf_stream.h | 31 ++
18 files changed, 1547 insertions(+)
base-commit: ab5fce87a778cb780a05984a2ca448f2b41aafbf
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
@ 2026-06-28 19:13 ` Jinseob Kim
2026-06-28 19:19 ` sashiko-bot
2026-06-29 15:39 ` Conor Dooley
2026-06-28 19:13 ` [PATCH RFC v6 2/5] Documentation: iio: add Open Sensor Fusion driver overview Jinseob Kim
` (5 subsequent siblings)
6 siblings, 2 replies; 16+ messages in thread
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Add a binding for the generic Open Sensor Fusion host interface.
Open Sensor Fusion devices report capabilities and samples over an OSF
protocol stream. Sensor channels are discovered at runtime from
capability reports instead of being described individually in Device
Tree.
The protocol version is discovered at runtime from the OSF frame header.
OSF GREEN is a product identity, and OSF0 is a wire-format magic value,
so neither is used as the Linux compatible string.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
.../bindings/iio/opensensorfusion,osf.yaml | 54 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 6 +++
3 files changed, 62 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
diff --git a/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
new file mode 100644
index 000000000..8016d582f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/opensensorfusion,osf.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Open Sensor Fusion Sensor Aggregation Hub
+
+maintainers:
+ - Jinseob Kim <kimjinseob88@gmail.com>
+
+description: |
+ This binding documents the generic Open Sensor Fusion host interface. Open
+ Sensor Fusion is a sensor aggregation hub. The hub exposes an OSF protocol
+ data stream over its host interface and reports capabilities and samples for
+ multiple sensor classes. The actual sensor channels are discovered at runtime
+ from OSF capability reports instead of describing them in Device Tree. The
+ protocol version is discovered at runtime.
+
+ Public project documentation is available at:
+
+ https://github.com/opensensorfusion
+
+ The compatible describes the generic Open Sensor Fusion host interface. It
+ is not an OSF GREEN board identity, and it does not encode the OSF0 wire
+ magic. OSF0, protocol_major, and protocol_minor are wire-protocol details
+ exchanged in OSF frames.
+
+allOf:
+ - $ref: /schemas/serial/serial-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: opensensorfusion,osf
+
+ vcc-supply:
+ description:
+ Regulator supplying power to the Open Sensor Fusion device.
+
+required:
+ - compatible
+ - vcc-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ serial {
+ sensor {
+ compatible = "opensensorfusion,osf";
+ vcc-supply = <&vcc_sensor>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 28784d66a..88172d4a4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1237,6 +1237,8 @@ patternProperties:
description: OpenPandora GmbH
"^openrisc,.*":
description: OpenRISC.io
+ "^opensensorfusion,.*":
+ description: Open Sensor Fusion
"^openwrt,.*":
description: OpenWrt
"^option,.*":
diff --git a/MAINTAINERS b/MAINTAINERS
index c2c6d7927..e4df9d8dc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20011,6 +20011,12 @@ F: Documentation/devicetree/
F: arch/*/boot/dts/
F: include/dt-bindings/
+OPEN SENSOR FUSION
+M: Jinseob Kim <kimjinseob88@gmail.com>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
+K: opensensorfusion
+
OPENCOMPUTE PTP CLOCK DRIVER
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: netdev@vger.kernel.org
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC v6 2/5] Documentation: iio: add Open Sensor Fusion driver overview
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device Jinseob Kim
@ 2026-06-28 19:13 ` Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 3/5] iio: osf: add protocol decoding Jinseob Kim
` (4 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Document the Linux IIO mapping for Open Sensor Fusion devices.
The overview explains that sensor channels are discovered at runtime
from mandatory capability reports. It also documents that OSF0 is a
wire-format detail and that protocol_major and protocol_minor carry
protocol compatibility information.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
Documentation/iio/index.rst | 1 +
Documentation/iio/open-sensor-fusion.rst | 72 ++++++++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 74 insertions(+)
create mode 100644 Documentation/iio/open-sensor-fusion.rst
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
index ba3e609c6..2713ec5e0 100644
--- a/Documentation/iio/index.rst
+++ b/Documentation/iio/index.rst
@@ -38,4 +38,5 @@ Industrial I/O Kernel Drivers
adxl345
bno055
ep93xx_adc
+ open-sensor-fusion
opt4060
diff --git a/Documentation/iio/open-sensor-fusion.rst b/Documentation/iio/open-sensor-fusion.rst
new file mode 100644
index 000000000..832901f5e
--- /dev/null
+++ b/Documentation/iio/open-sensor-fusion.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+Open Sensor Fusion
+==================
+
+Open Sensor Fusion is a sensor aggregation hub interface. The Linux IIO driver
+receives OSF protocol frames from an attached device and registers matching IIO
+devices for the sensor classes supported by the driver. The actual sensor
+channels are discovered at runtime from mandatory OSF capability reports.
+
+This document is a driver-facing overview for the Linux IIO mapping. The full
+wire protocol, firmware behavior, and hardware model details belong in the Open
+Sensor Fusion project documentation.
+
+Device Model
+------------
+
+An OSF device sends binary frames from the device to the host. Devices using the
+``opensensorfusion,osf`` compatible are expected to provide
+``CAPABILITY_REPORT`` messages so the host can discover which sensor streams are
+available. Device Tree describes the attached OSF sensor aggregation hub; it does
+not enumerate the individual sensors discovered at runtime.
+
+The currently supported Linux subset exposes:
+
+* accelerometer samples as ``IIO_ACCEL`` X/Y/Z channels,
+* gyroscope samples as ``IIO_ANGL_VEL`` X/Y/Z channels,
+* magnetometer samples as ``IIO_MAGN`` X/Y/Z channels, and
+* temperature samples as ``IIO_TEMP``.
+
+Protocol Scope
+---------------
+
+The driver supports OSF protocol major version 0 for the initial IIO receive
+path. The current wire magic is ``OSF0``; that string is a wire-format detail and
+is not the Linux driver identity. Device Tree keeps the generic
+``opensensorfusion,osf`` compatible rather than naming a product such as OSF
+GREEN or a wire magic value.
+
+Protocol versioning is carried by the ``protocol_major`` and ``protocol_minor``
+fields at fixed offsets in the OSF frame header. The driver currently
+supports ``protocol_major`` 0. ``protocol_minor`` changes within major version
+0 are intended to remain backward-compatible within the fixed header layout.
+Incompatible wire-format changes require a new ``protocol_major``. A future
+device that cannot expose compatible version discovery through that fixed
+header layout would need a different Device Tree compatible.
+
+The initial Linux driver handles device-to-host frames for:
+
+* ``SENSOR_SAMPLE`` buffered and direct-mode sample data,
+* ``CAPABILITY_REPORT`` based IIO device registration, and
+* ``DEVICE_STATUS`` cache updates.
+
+Vendor-private message types are ignored. Command transport, calibration
+control ABI, fusion output ABI, and runtime capability removal are outside the
+initial Linux IIO receive path.
+
+Timestamps
+----------
+
+OSF frames include a device-side ``timestamp_us`` field. Buffered IIO samples use
+an IIO timestamp captured on the host when samples are pushed to IIO buffers.
+The initial driver does not correlate the device timestamp with the host IIO
+clock.
+
+Compatibility Notes
+-------------------
+
+The project protocol documentation should define the compatibility rules for
+reserved fields, optional flags, and trailing extension data. Until those rules
+are finalized, the Linux decoder keeps conservative bounds checks around the
+currently supported message layouts.
diff --git a/MAINTAINERS b/MAINTAINERS
index e4df9d8dc..17c80b55b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20015,6 +20015,7 @@ OPEN SENSOR FUSION
M: Jinseob Kim <kimjinseob88@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
+F: Documentation/iio/open-sensor-fusion.rst
K: opensensorfusion
OPENCOMPUTE PTP CLOCK DRIVER
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC v6 3/5] iio: osf: add protocol decoding
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 2/5] Documentation: iio: add Open Sensor Fusion driver overview Jinseob Kim
@ 2026-06-28 19:13 ` Jinseob Kim
2026-06-29 14:05 ` Andy Shevchenko
2026-06-28 19:13 ` [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser Jinseob Kim
` (3 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Add helpers for decoding Open Sensor Fusion frame headers and supported
message payloads.
The decoder validates the OSF0 wire magic, protocol major version,
header length, payload bounds, reserved fields and CRC before exposing
decoded frame contents to the rest of the driver.
Use explicit little-endian wire storage sizes and designated
initializers for decoded output structures.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
MAINTAINERS | 1 +
drivers/iio/opensensorfusion/osf_protocol.c | 258 ++++++++++++++++++++
drivers/iio/opensensorfusion/osf_protocol.h | 97 ++++++++
3 files changed, 356 insertions(+)
create mode 100644 drivers/iio/opensensorfusion/osf_protocol.c
create mode 100644 drivers/iio/opensensorfusion/osf_protocol.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 17c80b55b..32d3e7674 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20016,6 +20016,7 @@ M: Jinseob Kim <kimjinseob88@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
F: Documentation/iio/open-sensor-fusion.rst
+F: drivers/iio/opensensorfusion/osf_protocol.*
K: opensensorfusion
OPENCOMPUTE PTP CLOCK DRIVER
diff --git a/drivers/iio/opensensorfusion/osf_protocol.c b/drivers/iio/opensensorfusion/osf_protocol.c
new file mode 100644
index 000000000..7e27ce3b0
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_protocol.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bits.h>
+#include <linux/crc32.h>
+#include <linux/errno.h>
+#include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "osf_protocol.h"
+
+#define OSF_CRC32_INIT GENMASK(31, 0)
+#define OSF_CRC32_XOROUT GENMASK(31, 0)
+#define OSF_FRAME_MAGIC 0x3046534f /* "OSF0" little-endian */
+
+static bool osf_sensor_type_valid(u16 sensor_type)
+{
+ return sensor_type >= OSF_SENSOR_ACCELEROMETER &&
+ sensor_type <= OSF_SENSOR_PROXIMITY;
+}
+
+static u32 osf_crc32_ieee(const u8 *buf, size_t len)
+{
+ return crc32_le(OSF_CRC32_INIT, buf, len) ^ OSF_CRC32_XOROUT;
+}
+
+int osf_protocol_decode_frame(const u8 *buf, size_t len,
+ struct osf_frame *frame, size_t *frame_len)
+{
+ u32 expected_crc;
+ u32 actual_crc;
+ u32 payload_len;
+ size_t total_len;
+ u8 major;
+
+ if (!buf || !frame || !frame_len)
+ return -EINVAL;
+
+ if (len < OSF_FRAME_MIN_LEN)
+ return -EMSGSIZE;
+
+ if (get_unaligned_le32(buf) != OSF_FRAME_MAGIC)
+ return -EPROTO;
+
+ major = buf[4];
+ if (major != OSF_PROTOCOL_MAJOR)
+ return -EPROTO;
+
+ if (get_unaligned_le16(buf + 6) != OSF_FRAME_HEADER_LEN)
+ return -EPROTO;
+
+ payload_len = get_unaligned_le32(buf + 10);
+ if (payload_len > len - OSF_FRAME_MIN_LEN)
+ return -EMSGSIZE;
+
+ if (get_unaligned_le32(buf + 34))
+ return -EPROTO;
+
+ total_len = OSF_FRAME_HEADER_LEN + payload_len + OSF_FRAME_CRC_LEN;
+ expected_crc = osf_crc32_ieee(buf, OSF_FRAME_HEADER_LEN + payload_len);
+ actual_crc = get_unaligned_le32(buf + OSF_FRAME_HEADER_LEN + payload_len);
+
+ if (actual_crc != expected_crc)
+ return -EBADMSG;
+
+ frame->protocol_minor = buf[5];
+ frame->message_type = get_unaligned_le16(buf + 8);
+ frame->payload_len = payload_len;
+ frame->sequence = get_unaligned_le64(buf + 14);
+ frame->timestamp_us = get_unaligned_le64(buf + 22);
+ frame->flags = get_unaligned_le32(buf + 30);
+ frame->payload = buf + OSF_FRAME_HEADER_LEN;
+ frame->crc = actual_crc;
+ *frame_len = total_len;
+
+ return 0;
+}
+
+int osf_protocol_decode_sensor_sample(const struct osf_frame *frame,
+ struct osf_sensor_sample *sample)
+{
+ u16 channel_count;
+ u16 sample_format;
+ u16 sensor_type;
+ size_t expected_len;
+ const u8 *payload;
+
+ if (!frame || !sample || !frame->payload)
+ return -EINVAL;
+
+ if (frame->message_type != OSF_MSG_SENSOR_SAMPLE)
+ return -EPROTO;
+
+ if (frame->payload_len < OSF_SENSOR_SAMPLE_BASE_LEN)
+ return -EMSGSIZE;
+
+ payload = frame->payload;
+ sensor_type = get_unaligned_le16(payload);
+ channel_count = get_unaligned_le16(payload + 4);
+ sample_format = get_unaligned_le16(payload + 6);
+
+ if (!osf_sensor_type_valid(sensor_type))
+ return -EPROTO;
+
+ if (!channel_count)
+ return -EPROTO;
+
+ if (sample_format != OSF_SAMPLE_FORMAT_S32)
+ return -EPROTO;
+
+ if (get_unaligned_le32(payload + 12))
+ return -EPROTO;
+
+ if (channel_count > (SIZE_MAX - OSF_SENSOR_SAMPLE_BASE_LEN) /
+ sizeof(__le32))
+ return -EOVERFLOW;
+
+ expected_len = OSF_SENSOR_SAMPLE_BASE_LEN + channel_count * sizeof(__le32);
+ if (frame->payload_len != expected_len)
+ return -EMSGSIZE;
+
+ *sample = (struct osf_sensor_sample) {
+ .sensor_type = sensor_type,
+ .sensor_index = get_unaligned_le16(payload + 2),
+ .channel_count = channel_count,
+ .sample_format = sample_format,
+ .scale_nano = get_unaligned_le32(payload + 8),
+ .samples = payload + OSF_SENSOR_SAMPLE_BASE_LEN,
+ };
+
+ return 0;
+}
+
+int osf_protocol_sensor_sample_value(const struct osf_sensor_sample *sample,
+ u16 index, s32 *value)
+{
+ if (!sample || !sample->samples || !value)
+ return -EINVAL;
+
+ if (index >= sample->channel_count)
+ return -ERANGE;
+
+ /* Samples are little-endian two's-complement signed values. */
+ *value = get_unaligned_le32(sample->samples + index * sizeof(__le32));
+
+ return 0;
+}
+
+int osf_protocol_decode_device_status(const struct osf_frame *frame,
+ struct osf_device_status *status)
+{
+ const u8 *payload;
+
+ if (!frame || !status || !frame->payload)
+ return -EINVAL;
+
+ if (frame->message_type != OSF_MSG_DEVICE_STATUS)
+ return -EPROTO;
+
+ if (frame->payload_len != OSF_DEVICE_STATUS_LEN)
+ return -EMSGSIZE;
+
+ payload = frame->payload;
+ if (get_unaligned_le32(payload + 16))
+ return -EPROTO;
+
+ *status = (struct osf_device_status) {
+ .uptime_s = get_unaligned_le32(payload),
+ .status_flags = get_unaligned_le32(payload + 4),
+ .error_flags = get_unaligned_le32(payload + 8),
+ .dropped_frames = get_unaligned_le32(payload + 12),
+ };
+
+ return 0;
+}
+
+int osf_protocol_decode_capability_report(const struct osf_frame *frame,
+ struct osf_capability_report *report)
+{
+ u16 capability_count;
+ size_t expected_len;
+ const u8 *payload;
+
+ if (!frame || !report || !frame->payload)
+ return -EINVAL;
+
+ if (frame->message_type != OSF_MSG_CAPABILITY_REPORT)
+ return -EPROTO;
+
+ if (frame->payload_len < OSF_CAP_REPORT_BASE_LEN)
+ return -EMSGSIZE;
+
+ payload = frame->payload;
+ capability_count = get_unaligned_le16(payload);
+
+ if (get_unaligned_le16(payload + 2))
+ return -EPROTO;
+
+ if (capability_count > (SIZE_MAX - OSF_CAP_REPORT_BASE_LEN) /
+ OSF_CAP_SENSOR_ENTRY_LEN)
+ return -EOVERFLOW;
+
+ expected_len = OSF_CAP_REPORT_BASE_LEN +
+ capability_count * OSF_CAP_SENSOR_ENTRY_LEN;
+ if (frame->payload_len != expected_len)
+ return -EMSGSIZE;
+
+ *report = (struct osf_capability_report) {
+ .capability_count = capability_count,
+ .entries = payload + OSF_CAP_REPORT_BASE_LEN,
+ };
+
+ return 0;
+}
+
+int osf_protocol_decode_capability_entry(const struct osf_capability_report
+ *report, u16 index,
+ struct osf_capability_entry *entry)
+{
+ u16 sample_format;
+ u16 sensor_type;
+ u32 flags;
+ const u8 *payload;
+
+ if (!report || !report->entries || !entry)
+ return -EINVAL;
+
+ if (index >= report->capability_count)
+ return -ERANGE;
+
+ payload = report->entries + index * OSF_CAP_SENSOR_ENTRY_LEN;
+ sensor_type = get_unaligned_le16(payload);
+ sample_format = get_unaligned_le16(payload + 6);
+ flags = get_unaligned_le32(payload + 12);
+
+ if (!osf_sensor_type_valid(sensor_type))
+ return -EPROTO;
+
+ if (sample_format != OSF_SAMPLE_FORMAT_S32)
+ return -EPROTO;
+
+ if (flags & ~OSF_CAPABILITY_FLAGS_MASK)
+ return -EPROTO;
+
+ if (get_unaligned_le32(payload + 16))
+ return -EPROTO;
+
+ *entry = (struct osf_capability_entry) {
+ .sensor_type = sensor_type,
+ .sensor_index = get_unaligned_le16(payload + 2),
+ .channel_count = get_unaligned_le16(payload + 4),
+ .sample_format = sample_format,
+ .scale_nano = get_unaligned_le32(payload + 8),
+ .flags = flags,
+ };
+
+ return 0;
+}
diff --git a/drivers/iio/opensensorfusion/osf_protocol.h b/drivers/iio/opensensorfusion/osf_protocol.h
new file mode 100644
index 000000000..479cb07af
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_protocol.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_PROTOCOL_H
+#define _OSF_PROTOCOL_H
+
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define OSF_PROTOCOL_MAJOR 0
+#define OSF_PROTOCOL_MINOR 0
+#define OSF_FRAME_HEADER_LEN 38
+#define OSF_FRAME_CRC_LEN 4
+#define OSF_FRAME_MIN_LEN (OSF_FRAME_HEADER_LEN + OSF_FRAME_CRC_LEN)
+
+#define OSF_SENSOR_SAMPLE_BASE_LEN 16
+#define OSF_DEVICE_STATUS_LEN 20
+#define OSF_CAP_REPORT_BASE_LEN 4
+#define OSF_CAP_SENSOR_ENTRY_LEN 20
+#define OSF_CAPABILITY_FLAGS_MASK GENMASK(1, 0)
+
+enum osf_message_type {
+ OSF_MSG_SENSOR_SAMPLE = 0x0001,
+ OSF_MSG_DEVICE_STATUS = 0x0002,
+ OSF_MSG_CAPABILITY_REPORT = 0x0003,
+};
+
+enum osf_sensor_type {
+ OSF_SENSOR_ACCELEROMETER = 0x0001,
+ OSF_SENSOR_GYROSCOPE = 0x0002,
+ OSF_SENSOR_MAGNETOMETER = 0x0003,
+ OSF_SENSOR_BAROMETER = 0x0004,
+ OSF_SENSOR_TEMPERATURE = 0x0005,
+ OSF_SENSOR_HUMIDITY = 0x0006,
+ OSF_SENSOR_AMBIENT_LIGHT = 0x0007,
+ OSF_SENSOR_PROXIMITY = 0x0008,
+};
+
+enum osf_sample_format {
+ OSF_SAMPLE_FORMAT_S32 = 0x0001,
+};
+
+struct osf_frame {
+ u8 protocol_minor;
+ u16 message_type;
+ u32 payload_len;
+ u64 sequence;
+ u64 timestamp_us;
+ u32 flags;
+ /* payload points into the caller-owned frame buffer. */
+ const u8 *payload;
+ u32 crc;
+};
+
+struct osf_sensor_sample {
+ u16 sensor_type;
+ u16 sensor_index;
+ u16 channel_count;
+ u16 sample_format;
+ u32 scale_nano;
+ const u8 *samples;
+};
+
+struct osf_device_status {
+ u32 uptime_s;
+ u32 status_flags;
+ u32 error_flags;
+ u32 dropped_frames;
+};
+
+struct osf_capability_report {
+ u16 capability_count;
+ const u8 *entries;
+};
+
+struct osf_capability_entry {
+ u16 sensor_type;
+ u16 sensor_index;
+ u16 channel_count;
+ u16 sample_format;
+ u32 scale_nano;
+ u32 flags;
+};
+
+int osf_protocol_decode_frame(const u8 *buf, size_t len,
+ struct osf_frame *frame, size_t *frame_len);
+int osf_protocol_decode_sensor_sample(const struct osf_frame *frame,
+ struct osf_sensor_sample *sample);
+int osf_protocol_decode_device_status(const struct osf_frame *frame,
+ struct osf_device_status *status);
+int osf_protocol_decode_capability_report(const struct osf_frame *frame,
+ struct osf_capability_report *report);
+int osf_protocol_decode_capability_entry(const struct osf_capability_report
+ *report, u16 index,
+ struct osf_capability_entry *entry);
+int osf_protocol_sensor_sample_value(const struct osf_sensor_sample *sample,
+ u16 index, s32 *value);
+
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
` (2 preceding siblings ...)
2026-06-28 19:13 ` [PATCH RFC v6 3/5] iio: osf: add protocol decoding Jinseob Kim
@ 2026-06-28 19:13 ` Jinseob Kim
2026-06-28 19:26 ` sashiko-bot
2026-06-29 14:10 ` Andy Shevchenko
2026-06-28 19:13 ` [PATCH RFC v6 5/5] iio: osf: add UART IIO driver Jinseob Kim
` (2 subsequent siblings)
6 siblings, 2 replies; 16+ messages in thread
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Add a UART byte-stream parser for Open Sensor Fusion frames.
The parser searches for the OSF0 wire magic, keeps partial frames
buffered, checks header length and payload bounds, and passes complete
candidate frames to the core decoder.
Rejected candidate frames drop only the current head byte before
resynchronizing, so a corrupted unauthenticated payload length cannot
make the parser skip later valid frames.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
MAINTAINERS | 1 +
drivers/iio/opensensorfusion/osf_stream.c | 189 ++++++++++++++++++++++
drivers/iio/opensensorfusion/osf_stream.h | 31 ++++
3 files changed, 221 insertions(+)
create mode 100644 drivers/iio/opensensorfusion/osf_stream.c
create mode 100644 drivers/iio/opensensorfusion/osf_stream.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 32d3e7674..3d4199d9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20017,6 +20017,7 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
F: Documentation/iio/open-sensor-fusion.rst
F: drivers/iio/opensensorfusion/osf_protocol.*
+F: drivers/iio/opensensorfusion/osf_stream.*
K: opensensorfusion
OPENCOMPUTE PTP CLOCK DRIVER
diff --git a/drivers/iio/opensensorfusion/osf_stream.c b/drivers/iio/opensensorfusion/osf_stream.c
new file mode 100644
index 000000000..470b4ec1f
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_stream.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "osf_core.h"
+#include "osf_protocol.h"
+#include "osf_stream.h"
+
+#define OSF_STREAM_MAGIC_LEN 4
+#define OSF_STREAM_MAX_PAYLOAD_LEN \
+ (OSF_STREAM_MAX_FRAME_LEN - OSF_FRAME_HEADER_LEN - OSF_FRAME_CRC_LEN)
+
+static const u8 osf_stream_magic[OSF_STREAM_MAGIC_LEN] = {
+ 'O', 'S', 'F', '0',
+};
+
+static void osf_stream_discard(struct osf_stream *stream, size_t count)
+{
+ if (count >= stream->len) {
+ stream->len = 0;
+ return;
+ }
+
+ memmove(stream->buf, stream->buf + count, stream->len - count);
+ stream->len -= count;
+}
+
+static void osf_stream_drop_invalid_head(struct osf_stream *stream)
+{
+ osf_stream_discard(stream, 1);
+}
+
+static bool osf_stream_magic_match(const u8 *buf, size_t len)
+{
+ return !memcmp(buf, osf_stream_magic, len);
+}
+
+static size_t osf_stream_discard_to_magic(struct osf_stream *stream)
+{
+ size_t old_len = stream->len;
+ size_t match_len;
+ size_t i;
+
+ for (i = 0; i < stream->len; i++) {
+ match_len = stream->len - i;
+ if (match_len > OSF_STREAM_MAGIC_LEN)
+ match_len = OSF_STREAM_MAGIC_LEN;
+
+ if (osf_stream_magic_match(stream->buf + i, match_len)) {
+ if (i)
+ osf_stream_discard(stream, i);
+ return i;
+ }
+ }
+
+ stream->len = 0;
+ return old_len;
+}
+
+static int osf_stream_process(struct osf_stream *stream)
+{
+ size_t discarded;
+ size_t frame_len;
+ u32 payload_len;
+ int first_err = 0;
+ int ret;
+
+ while (stream->len) {
+ discarded = osf_stream_discard_to_magic(stream);
+ if (discarded) {
+ stream->stats.bad_magic_resyncs++;
+ stream->stats.dropped_bytes += discarded;
+ if (!first_err)
+ first_err = -EPROTO;
+ }
+
+ if (!stream->len)
+ break;
+
+ if (stream->len < OSF_FRAME_HEADER_LEN)
+ break;
+
+ if (get_unaligned_le16(stream->buf + 6) !=
+ OSF_FRAME_HEADER_LEN) {
+ stream->stats.dropped_bytes++;
+ osf_stream_drop_invalid_head(stream);
+ if (!first_err)
+ first_err = -EPROTO;
+ continue;
+ }
+
+ payload_len = get_unaligned_le32(stream->buf + 10);
+ if (payload_len > OSF_STREAM_MAX_PAYLOAD_LEN) {
+ stream->stats.dropped_bytes++;
+ osf_stream_drop_invalid_head(stream);
+ if (!first_err)
+ first_err = -EMSGSIZE;
+ continue;
+ }
+
+ frame_len = OSF_FRAME_HEADER_LEN + payload_len + OSF_FRAME_CRC_LEN;
+ if (stream->len < frame_len)
+ break;
+
+ ret = osf_core_receive_frame(stream->osf, stream->buf, frame_len);
+ if (ret) {
+ if (ret == -EBADMSG)
+ stream->stats.bad_crc_frames++;
+
+ /*
+ * Until the decoder accepts the frame, payload_len is
+ * untrusted. Drop only the current head and resynchronize.
+ */
+ stream->stats.dropped_bytes++;
+ osf_stream_drop_invalid_head(stream);
+ if (!first_err)
+ first_err = ret;
+ continue;
+ }
+
+ stream->stats.valid_frames++;
+ osf_stream_discard(stream, frame_len);
+ }
+
+ return first_err;
+}
+
+void osf_stream_init(struct osf_stream *stream, struct osf_device *osf)
+{
+ if (!stream)
+ return;
+
+ stream->osf = osf;
+ stream->len = 0;
+ memset(&stream->stats, 0, sizeof(stream->stats));
+}
+
+void osf_stream_reset(struct osf_stream *stream)
+{
+ if (stream) {
+ stream->len = 0;
+ memset(&stream->stats, 0, sizeof(stream->stats));
+ }
+}
+
+int osf_stream_receive_bytes(struct osf_stream *stream, const u8 *buf,
+ size_t len)
+{
+ size_t copy_len;
+ size_t space;
+ int first_err = 0;
+ int ret;
+
+ if (!stream || !stream->osf || (!buf && len))
+ return -EINVAL;
+
+ if (!len) {
+ ret = osf_stream_process(stream);
+ if (ret && !first_err)
+ first_err = ret;
+ return first_err;
+ }
+
+ while (len) {
+ space = OSF_STREAM_MAX_FRAME_LEN - stream->len;
+ if (!space) {
+ stream->stats.dropped_bytes++;
+ osf_stream_discard(stream, 1);
+ if (!first_err)
+ first_err = -EMSGSIZE;
+ continue;
+ }
+
+ copy_len = len < space ? len : space;
+ memcpy(stream->buf + stream->len, buf, copy_len);
+ stream->len += copy_len;
+ buf += copy_len;
+ len -= copy_len;
+
+ ret = osf_stream_process(stream);
+ if (ret && !first_err)
+ first_err = ret;
+ }
+
+ return first_err;
+}
diff --git a/drivers/iio/opensensorfusion/osf_stream.h b/drivers/iio/opensensorfusion/osf_stream.h
new file mode 100644
index 000000000..f7f9477fe
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_stream.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_STREAM_H
+#define _OSF_STREAM_H
+
+#include <linux/types.h>
+
+#define OSF_STREAM_MAX_FRAME_LEN 4096
+
+struct osf_device;
+
+struct osf_stream_stats {
+ u64 valid_frames;
+ u64 bad_magic_resyncs;
+ u64 bad_crc_frames;
+ u64 partial_frames;
+ u64 dropped_bytes;
+};
+
+struct osf_stream {
+ struct osf_device *osf;
+ u8 buf[OSF_STREAM_MAX_FRAME_LEN];
+ size_t len;
+ struct osf_stream_stats stats;
+};
+
+void osf_stream_init(struct osf_stream *stream, struct osf_device *osf);
+void osf_stream_reset(struct osf_stream *stream);
+int osf_stream_receive_bytes(struct osf_stream *stream, const u8 *buf,
+ size_t len);
+
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC v6 5/5] iio: osf: add UART IIO driver
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
` (3 preceding siblings ...)
2026-06-28 19:13 ` [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser Jinseob Kim
@ 2026-06-28 19:13 ` Jinseob Kim
2026-06-28 19:26 ` sashiko-bot
2026-06-29 14:09 ` [PATCH RFC v6 0/5] iio: add Open Sensor Fusion " Andy Shevchenko
2026-06-29 15:25 ` David Lechner
6 siblings, 1 reply; 16+ messages in thread
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Add the Open Sensor Fusion serdev transport, driver core, and IIO
registration path as one complete driver patch.
The driver enables the required vcc regulator, receives OSF frames over
UART, registers IIO devices from capability reports, supports direct raw
reads from the latest sample cache, and pushes buffered samples into
software kfifo buffers.
Use final Kconfig and Makefile contents from the start, claim IIO buffer
mode while pushing samples, and use zeroed scan storage with explicit
timestamp alignment so the driver does not depend on IIO core
bounce-buffer padding behavior.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
MAINTAINERS | 5 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/opensensorfusion/Kconfig | 16 ++
drivers/iio/opensensorfusion/Makefile | 6 +
drivers/iio/opensensorfusion/osf_core.c | 291 ++++++++++++++++++++
drivers/iio/opensensorfusion/osf_core.h | 70 +++++
drivers/iio/opensensorfusion/osf_iio.c | 308 ++++++++++++++++++++++
drivers/iio/opensensorfusion/osf_iio.h | 22 ++
drivers/iio/opensensorfusion/osf_serdev.c | 114 ++++++++
10 files changed, 834 insertions(+)
create mode 100644 drivers/iio/opensensorfusion/Kconfig
create mode 100644 drivers/iio/opensensorfusion/Makefile
create mode 100644 drivers/iio/opensensorfusion/osf_core.c
create mode 100644 drivers/iio/opensensorfusion/osf_core.h
create mode 100644 drivers/iio/opensensorfusion/osf_iio.c
create mode 100644 drivers/iio/opensensorfusion/osf_iio.h
create mode 100644 drivers/iio/opensensorfusion/osf_serdev.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d4199d9e..6ce18ad92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20016,7 +20016,12 @@ M: Jinseob Kim <kimjinseob88@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
F: Documentation/iio/open-sensor-fusion.rst
+F: drivers/iio/opensensorfusion/Kconfig
+F: drivers/iio/opensensorfusion/Makefile
+F: drivers/iio/opensensorfusion/osf_core.*
+F: drivers/iio/opensensorfusion/osf_iio.*
F: drivers/iio/opensensorfusion/osf_protocol.*
+F: drivers/iio/opensensorfusion/osf_serdev.c
F: drivers/iio/opensensorfusion/osf_stream.*
K: opensensorfusion
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 661127aed..939f6c546 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -101,6 +101,7 @@ source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
source "drivers/iio/multiplexer/Kconfig"
source "drivers/iio/orientation/Kconfig"
+source "drivers/iio/opensensorfusion/Kconfig"
source "drivers/iio/test/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index cb80ef837..d864fe17b 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -37,6 +37,7 @@ obj-y += light/
obj-y += magnetometer/
obj-y += multiplexer/
obj-y += orientation/
+obj-y += opensensorfusion/
obj-y += position/
obj-y += potentiometer/
obj-y += potentiostat/
diff --git a/drivers/iio/opensensorfusion/Kconfig b/drivers/iio/opensensorfusion/Kconfig
new file mode 100644
index 000000000..6da44f91c
--- /dev/null
+++ b/drivers/iio/opensensorfusion/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config OPEN_SENSOR_FUSION
+ tristate "Open Sensor Fusion UART IIO driver"
+ depends on IIO
+ depends on SERIAL_DEV_BUS
+ select CRC32
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Build the Open Sensor Fusion UART IIO driver.
+
+ The driver receives OSF protocol frames over a serdev UART and
+ registers IIO devices for supported capability entries. It exposes
+ accelerometer, gyroscope, magnetometer, and temperature samples
+ through IIO direct reads and software buffers.
diff --git a/drivers/iio/opensensorfusion/Makefile b/drivers/iio/opensensorfusion/Makefile
new file mode 100644
index 000000000..b4e03b80c
--- /dev/null
+++ b/drivers/iio/opensensorfusion/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_OPEN_SENSOR_FUSION) += open-sensor-fusion.o
+
+open-sensor-fusion-y := osf_core.o osf_iio.o osf_protocol.o osf_serdev.o \
+ osf_stream.o
diff --git a/drivers/iio/opensensorfusion/osf_core.c b/drivers/iio/opensensorfusion/osf_core.c
new file mode 100644
index 000000000..207de03db
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_core.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/cleanup.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "osf_core.h"
+#include "osf_iio.h"
+
+#define OSF_RESERVED_MSG_FIRST 0x7f00
+#define OSF_RESERVED_MSG_LAST 0x7fff
+#define OSF_VENDOR_PRIVATE_FIRST 0x8000
+
+void osf_core_init(struct osf_device *osf, struct device *dev)
+{
+ *osf = (struct osf_device) {
+ .dev = dev,
+ };
+ mutex_init(&osf->latest_lock);
+}
+
+void osf_core_unregister_iio(struct osf_device *osf)
+{
+ for (unsigned int i = 0; i < osf->iio_dev_count; i++)
+ osf_iio_unregister_sensor(osf->iio_devs[i].indio_dev);
+
+ osf->iio_dev_count = 0;
+}
+
+static struct iio_dev *osf_core_find_iio_dev(struct osf_device *osf,
+ u16 sensor_type, u16 sensor_index)
+{
+ const struct osf_iio_binding *binding;
+
+ for (unsigned int i = 0; i < osf->iio_dev_count; i++) {
+ binding = &osf->iio_devs[i];
+ if (binding->sensor_type == sensor_type &&
+ binding->sensor_index == sensor_index)
+ return binding->indio_dev;
+ }
+
+ return NULL;
+}
+
+static struct osf_latest_sample *
+osf_core_find_latest_sample(struct osf_device *osf, u16 sensor_type,
+ u16 sensor_index)
+{
+ struct osf_latest_sample *latest;
+
+ for (unsigned int i = 0; i < osf->latest_sample_count; i++) {
+ latest = &osf->latest_samples[i];
+ if (latest->sensor_type == sensor_type &&
+ latest->sensor_index == sensor_index)
+ return latest;
+ }
+
+ if (osf->latest_sample_count >= OSF_MAX_CAPABILITIES)
+ return NULL;
+
+ return &osf->latest_samples[osf->latest_sample_count++];
+}
+
+static bool osf_core_capability_is_duplicate(const struct osf_capability_cache *cache,
+ u16 index)
+{
+ const struct osf_capability_entry *entry = &cache->entries[index];
+
+ for (u16 i = 0; i < index; i++) {
+ if (!osf_iio_sensor_supported(cache->entries[i].sensor_type,
+ cache->entries[i].channel_count))
+ continue;
+
+ if (cache->entries[i].sensor_type == entry->sensor_type &&
+ cache->entries[i].sensor_index == entry->sensor_index)
+ return true;
+ }
+
+ return false;
+}
+
+static int osf_core_register_capabilities(struct osf_device *osf,
+ const struct osf_capability_cache *cache)
+{
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (osf->capability_cache.valid)
+ return 0;
+
+ for (u16 i = 0; i < cache->capability_count; i++) {
+ if (!osf_iio_sensor_supported(cache->entries[i].sensor_type,
+ cache->entries[i].channel_count))
+ continue;
+
+ if (osf_core_capability_is_duplicate(cache, i))
+ return -EEXIST;
+ }
+
+ for (u16 i = 0; i < cache->capability_count; i++) {
+ if (!osf_iio_sensor_supported(cache->entries[i].sensor_type,
+ cache->entries[i].channel_count))
+ continue;
+
+ ret = osf_iio_register_sensor(osf->dev, &cache->entries[i],
+ osf, &indio_dev);
+ if (ret)
+ goto err_unregister;
+
+ osf->iio_devs[osf->iio_dev_count++] = (struct osf_iio_binding) {
+ .sensor_type = cache->entries[i].sensor_type,
+ .sensor_index = cache->entries[i].sensor_index,
+ .indio_dev = indio_dev,
+ };
+ }
+
+ return 0;
+
+err_unregister:
+ osf_core_unregister_iio(osf);
+
+ return ret;
+}
+
+static int osf_core_handle_sensor_sample(struct osf_device *osf,
+ const struct osf_frame *frame)
+{
+ struct osf_latest_sample *latest;
+ struct osf_sensor_sample sample;
+ struct iio_dev *indio_dev;
+ s32 values[OSF_MAX_SAMPLE_CHANNELS] = { };
+ int ret;
+
+ ret = osf_protocol_decode_sensor_sample(frame, &sample);
+ if (ret)
+ return ret;
+
+ if (sample.channel_count > OSF_MAX_SAMPLE_CHANNELS)
+ return -E2BIG;
+
+ for (u16 i = 0; i < sample.channel_count; i++) {
+ ret = osf_protocol_sensor_sample_value(&sample, i, &values[i]);
+ if (ret)
+ return ret;
+ }
+
+ scoped_guard(mutex, &osf->latest_lock) {
+ latest = osf_core_find_latest_sample(osf, sample.sensor_type,
+ sample.sensor_index);
+ if (!latest)
+ return -E2BIG;
+
+ memcpy(latest->values, values, sizeof(values));
+ latest->sensor_type = sample.sensor_type;
+ latest->sensor_index = sample.sensor_index;
+ latest->channel_count = sample.channel_count;
+ latest->sample_format = sample.sample_format;
+ latest->scale_nano = sample.scale_nano;
+ latest->sequence = frame->sequence;
+ latest->timestamp_us = frame->timestamp_us;
+ latest->valid = true;
+ osf->last_sequence = frame->sequence;
+ }
+
+ indio_dev = osf_core_find_iio_dev(osf, sample.sensor_type,
+ sample.sensor_index);
+ if (!indio_dev)
+ return 0;
+
+ return osf_iio_push_sample(indio_dev, values, sample.channel_count);
+}
+
+static int osf_core_handle_device_status(struct osf_device *osf,
+ const struct osf_frame *frame)
+{
+ struct osf_device_status status;
+ int ret;
+
+ ret = osf_protocol_decode_device_status(frame, &status);
+ if (ret)
+ return ret;
+
+ osf->status_cache = (struct osf_status_cache) {
+ .uptime_s = status.uptime_s,
+ .status_flags = status.status_flags,
+ .error_flags = status.error_flags,
+ .dropped_frames = status.dropped_frames,
+ .sequence = frame->sequence,
+ .valid = true,
+ };
+ osf->last_sequence = frame->sequence;
+
+ return 0;
+}
+
+static int osf_core_handle_capability_report(struct osf_device *osf,
+ const struct osf_frame *frame)
+{
+ struct osf_capability_cache cache = { };
+ struct osf_capability_report report;
+ int ret;
+
+ ret = osf_protocol_decode_capability_report(frame, &report);
+ if (ret)
+ return ret;
+
+ if (report.capability_count > OSF_MAX_CAPABILITIES)
+ return -E2BIG;
+
+ if (osf->capability_cache.valid) {
+ osf->last_sequence = frame->sequence;
+ return 0;
+ }
+
+ for (u16 i = 0; i < report.capability_count; i++) {
+ ret = osf_protocol_decode_capability_entry(&report, i,
+ &cache.entries[i]);
+ if (ret)
+ return ret;
+ }
+
+ cache.capability_count = report.capability_count;
+ cache.sequence = frame->sequence;
+ cache.valid = true;
+
+ ret = osf_core_register_capabilities(osf, &cache);
+ if (ret)
+ return ret;
+
+ osf->capability_cache = cache;
+ osf->last_sequence = frame->sequence;
+
+ return 0;
+}
+
+int osf_core_receive_frame(struct osf_device *osf, const u8 *buf, size_t len)
+{
+ struct osf_frame frame;
+ size_t frame_len;
+ int ret;
+
+ ret = osf_protocol_decode_frame(buf, len, &frame, &frame_len);
+ if (ret)
+ return ret;
+
+ if (frame_len != len)
+ return -EMSGSIZE;
+
+ switch (frame.message_type) {
+ case OSF_MSG_SENSOR_SAMPLE:
+ return osf_core_handle_sensor_sample(osf, &frame);
+ case OSF_MSG_DEVICE_STATUS:
+ return osf_core_handle_device_status(osf, &frame);
+ case OSF_MSG_CAPABILITY_REPORT:
+ return osf_core_handle_capability_report(osf, &frame);
+ default:
+ if (frame.message_type >= OSF_RESERVED_MSG_FIRST &&
+ frame.message_type <= OSF_RESERVED_MSG_LAST)
+ return 0;
+ if (frame.message_type >= OSF_VENDOR_PRIVATE_FIRST)
+ return 0;
+ return -EOPNOTSUPP;
+ }
+}
+
+int osf_core_read_latest_sample(struct osf_device *osf, u16 sensor_type,
+ u16 sensor_index, u16 channel,
+ s32 *value)
+{
+ const struct osf_latest_sample *latest;
+
+ if (!osf || !value)
+ return -EINVAL;
+
+ guard(mutex)(&osf->latest_lock);
+ for (unsigned int i = 0; i < osf->latest_sample_count; i++) {
+ latest = &osf->latest_samples[i];
+ if (latest->sensor_type != sensor_type ||
+ latest->sensor_index != sensor_index)
+ continue;
+
+ if (!latest->valid || channel >= latest->channel_count)
+ break;
+
+ *value = latest->values[channel];
+ return 0;
+ }
+
+ return -ENODATA;
+}
diff --git a/drivers/iio/opensensorfusion/osf_core.h b/drivers/iio/opensensorfusion/osf_core.h
new file mode 100644
index 000000000..5744a39cf
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_core.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_CORE_H
+#define _OSF_CORE_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include "osf_protocol.h"
+
+#define OSF_MAX_SAMPLE_CHANNELS 3
+#define OSF_MAX_CAPABILITIES 16
+
+struct device;
+struct iio_dev;
+
+struct osf_latest_sample {
+ u16 sensor_type;
+ u16 sensor_index;
+ u16 channel_count;
+ u16 sample_format;
+ u32 scale_nano;
+ s32 values[OSF_MAX_SAMPLE_CHANNELS];
+ u64 sequence;
+ u64 timestamp_us;
+ bool valid;
+};
+
+struct osf_capability_cache {
+ u16 capability_count;
+ struct osf_capability_entry entries[OSF_MAX_CAPABILITIES];
+ u64 sequence;
+ bool valid;
+};
+
+struct osf_status_cache {
+ u32 uptime_s;
+ u32 status_flags;
+ u32 error_flags;
+ u32 dropped_frames;
+ u64 sequence;
+ bool valid;
+};
+
+struct osf_iio_binding {
+ u16 sensor_type;
+ u16 sensor_index;
+ struct iio_dev *indio_dev;
+};
+
+struct osf_device {
+ struct device *dev;
+ /* Protects latest_samples and latest_sample_count. */
+ struct mutex latest_lock;
+ struct osf_latest_sample latest_samples[OSF_MAX_CAPABILITIES];
+ unsigned int latest_sample_count;
+ struct osf_capability_cache capability_cache;
+ struct osf_status_cache status_cache;
+ struct osf_iio_binding iio_devs[OSF_MAX_CAPABILITIES];
+ unsigned int iio_dev_count;
+ u64 last_sequence;
+};
+
+void osf_core_init(struct osf_device *osf, struct device *dev);
+void osf_core_unregister_iio(struct osf_device *osf);
+int osf_core_receive_frame(struct osf_device *osf, const u8 *buf, size_t len);
+int osf_core_read_latest_sample(struct osf_device *osf, u16 sensor_type,
+ u16 sensor_index, u16 channel,
+ s32 *value);
+
+#endif
diff --git a/drivers/iio/opensensorfusion/osf_iio.c b/drivers/iio/opensensorfusion/osf_iio.c
new file mode 100644
index 000000000..91afcf3b8
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_iio.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include "osf_core.h"
+#include "osf_iio.h"
+
+struct osf_iio_sensor_spec {
+ u16 sensor_type;
+ u16 channel_count;
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ const unsigned long *available_scan_masks;
+};
+
+struct osf_iio_state {
+ const struct osf_iio_sensor_spec *spec;
+ struct iio_buffer *buffer;
+ u32 scale_nano;
+ u16 sensor_index;
+ struct osf_device *osf;
+};
+
+struct osf_iio_scan_3axis {
+ s32 values[3];
+ aligned_s64 timestamp;
+};
+
+struct osf_iio_scan_1axis {
+ s32 value;
+ aligned_s64 timestamp;
+};
+
+#define OSF_SCAN_TYPE_S32 \
+ { \
+ .sign = 's', \
+ .realbits = 32, \
+ .storagebits = 32, \
+ .endianness = IIO_CPU, \
+ }
+
+#define OSF_MOD_CHAN(_type, _mod, _idx) \
+ { \
+ .type = (_type), \
+ .modified = 1, \
+ .channel2 = (_mod), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = (_idx), \
+ .scan_type = OSF_SCAN_TYPE_S32, \
+ }
+
+#define OSF_CHAN(_type, _idx) \
+ { \
+ .type = (_type), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = (_idx), \
+ .scan_type = OSF_SCAN_TYPE_S32, \
+ }
+
+static const struct iio_chan_spec osf_accel_channels[] = {
+ OSF_MOD_CHAN(IIO_ACCEL, IIO_MOD_X, 0),
+ OSF_MOD_CHAN(IIO_ACCEL, IIO_MOD_Y, 1),
+ OSF_MOD_CHAN(IIO_ACCEL, IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec osf_gyro_channels[] = {
+ OSF_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_X, 0),
+ OSF_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, 1),
+ OSF_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec osf_mag_channels[] = {
+ OSF_MOD_CHAN(IIO_MAGN, IIO_MOD_X, 0),
+ OSF_MOD_CHAN(IIO_MAGN, IIO_MOD_Y, 1),
+ OSF_MOD_CHAN(IIO_MAGN, IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec osf_temp_channels[] = {
+ OSF_CHAN(IIO_TEMP, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const unsigned long osf_3axis_available_scan_masks[] = {
+ GENMASK(2, 0),
+ 0
+};
+
+static const struct osf_iio_sensor_spec osf_iio_sensor_specs[] = {
+ {
+ .sensor_type = OSF_SENSOR_ACCELEROMETER,
+ .channel_count = 3,
+ .name = "osf-accel",
+ .channels = osf_accel_channels,
+ .num_channels = ARRAY_SIZE(osf_accel_channels),
+ .available_scan_masks = osf_3axis_available_scan_masks,
+ },
+ {
+ .sensor_type = OSF_SENSOR_GYROSCOPE,
+ .channel_count = 3,
+ .name = "osf-gyro",
+ .channels = osf_gyro_channels,
+ .num_channels = ARRAY_SIZE(osf_gyro_channels),
+ .available_scan_masks = osf_3axis_available_scan_masks,
+ },
+ {
+ .sensor_type = OSF_SENSOR_MAGNETOMETER,
+ .channel_count = 3,
+ .name = "osf-magn",
+ .channels = osf_mag_channels,
+ .num_channels = ARRAY_SIZE(osf_mag_channels),
+ .available_scan_masks = osf_3axis_available_scan_masks,
+ },
+ {
+ .sensor_type = OSF_SENSOR_TEMPERATURE,
+ .channel_count = 1,
+ .name = "osf-temp",
+ .channels = osf_temp_channels,
+ .num_channels = ARRAY_SIZE(osf_temp_channels),
+ },
+};
+
+static const struct osf_iio_sensor_spec *
+osf_iio_find_sensor_spec(u16 sensor_type, u16 channel_count)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(osf_iio_sensor_specs); i++) {
+ if (osf_iio_sensor_specs[i].sensor_type == sensor_type &&
+ osf_iio_sensor_specs[i].channel_count == channel_count)
+ return &osf_iio_sensor_specs[i];
+ }
+
+ return NULL;
+}
+
+bool osf_iio_sensor_supported(u16 sensor_type, u16 channel_count)
+{
+ if (osf_iio_find_sensor_spec(sensor_type, channel_count))
+ return true;
+
+ return false;
+}
+
+const char *osf_iio_sensor_name(u16 sensor_type)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(osf_iio_sensor_specs); i++) {
+ if (osf_iio_sensor_specs[i].sensor_type == sensor_type)
+ return osf_iio_sensor_specs[i].name;
+ }
+
+ return NULL;
+}
+
+static int osf_iio_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long mask)
+{
+ struct osf_iio_state *state = iio_priv(indio_dev);
+ s32 raw;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = osf_core_read_latest_sample(state->osf,
+ state->spec->sensor_type,
+ state->sensor_index,
+ chan->scan_index, &raw);
+ if (ret)
+ return ret;
+
+ *val = raw;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = state->scale_nano / NANO;
+ *val2 = state->scale_nano % NANO;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info osf_iio_info = {
+ .read_raw = osf_iio_read_raw,
+};
+
+int osf_iio_register_sensor(struct device *dev,
+ const struct osf_capability_entry *entry,
+ struct osf_device *osf, struct iio_dev **indio_dev)
+{
+ const struct osf_iio_sensor_spec *spec;
+ struct osf_iio_state *state;
+ struct iio_dev *iio_dev;
+ int ret;
+
+ spec = osf_iio_find_sensor_spec(entry->sensor_type,
+ entry->channel_count);
+ if (!spec)
+ return -EOPNOTSUPP;
+
+ if (entry->sample_format != OSF_SAMPLE_FORMAT_S32)
+ return -EOPNOTSUPP;
+
+ iio_dev = iio_device_alloc(dev, sizeof(*state));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ state = iio_priv(iio_dev);
+ state->spec = spec;
+ state->scale_nano = entry->scale_nano;
+ state->sensor_index = entry->sensor_index;
+ state->osf = osf;
+
+ iio_dev->name = spec->name;
+ iio_dev->info = &osf_iio_info;
+ iio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ iio_dev->channels = spec->channels;
+ iio_dev->num_channels = spec->num_channels;
+ iio_dev->available_scan_masks = spec->available_scan_masks;
+
+ state->buffer = iio_kfifo_allocate();
+ if (!state->buffer) {
+ ret = -ENOMEM;
+ goto err_free_iio;
+ }
+
+ ret = iio_device_attach_buffer(iio_dev, state->buffer);
+ if (ret)
+ goto err_free_buffer;
+
+ ret = iio_device_register(iio_dev);
+ if (ret)
+ goto err_free_buffer;
+
+ *indio_dev = iio_dev;
+
+ return 0;
+
+err_free_buffer:
+ iio_kfifo_free(state->buffer);
+err_free_iio:
+ iio_device_free(iio_dev);
+
+ return ret;
+}
+
+void osf_iio_unregister_sensor(struct iio_dev *indio_dev)
+{
+ struct osf_iio_state *state = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_kfifo_free(state->buffer);
+ iio_device_free(indio_dev);
+}
+
+int osf_iio_push_sample(struct iio_dev *indio_dev, const s32 *values,
+ u16 channel_count)
+{
+ struct osf_iio_state *state = iio_priv(indio_dev);
+ s64 timestamp;
+ int ret;
+
+ if (channel_count != state->spec->channel_count)
+ return -EPROTO;
+
+ if (!iio_device_try_claim_buffer_mode(indio_dev))
+ return 0;
+
+ timestamp = iio_get_time_ns(indio_dev);
+
+ switch (channel_count) {
+ case 1: {
+ struct osf_iio_scan_1axis scan = { };
+
+ scan.value = values[0];
+ ret = iio_push_to_buffers_with_ts(indio_dev, &scan,
+ sizeof(scan), timestamp);
+ break;
+ }
+ case 3: {
+ struct osf_iio_scan_3axis scan = { };
+
+ scan.values[0] = values[0];
+ scan.values[1] = values[1];
+ scan.values[2] = values[2];
+ ret = iio_push_to_buffers_with_ts(indio_dev, &scan,
+ sizeof(scan), timestamp);
+ break;
+ }
+ default:
+ ret = -EPROTO;
+ break;
+ }
+
+ iio_device_release_buffer_mode(indio_dev);
+
+ return ret;
+}
diff --git a/drivers/iio/opensensorfusion/osf_iio.h b/drivers/iio/opensensorfusion/osf_iio.h
new file mode 100644
index 000000000..d0745167f
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_iio.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_IIO_H
+#define _OSF_IIO_H
+
+#include <linux/types.h>
+
+#include "osf_protocol.h"
+
+struct device;
+struct iio_dev;
+struct osf_device;
+
+int osf_iio_register_sensor(struct device *dev,
+ const struct osf_capability_entry *entry,
+ struct osf_device *osf, struct iio_dev **indio_dev);
+void osf_iio_unregister_sensor(struct iio_dev *indio_dev);
+int osf_iio_push_sample(struct iio_dev *indio_dev, const s32 *values,
+ u16 channel_count);
+bool osf_iio_sensor_supported(u16 sensor_type, u16 channel_count);
+const char *osf_iio_sensor_name(u16 sensor_type);
+
+#endif
diff --git a/drivers/iio/opensensorfusion/osf_serdev.c b/drivers/iio/opensensorfusion/osf_serdev.c
new file mode 100644
index 000000000..474fa251f
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_serdev.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serdev.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "osf_core.h"
+#include "osf_stream.h"
+
+#define OSF_SERDEV_BAUD 115200
+
+struct osf_serdev {
+ struct serdev_device *serdev;
+ struct osf_device osf;
+ struct osf_stream stream;
+};
+
+static size_t osf_serdev_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t count)
+{
+ struct osf_serdev *osf_uart = serdev_device_get_drvdata(serdev);
+ const struct osf_stream_stats *stats;
+ u64 valid_before;
+ int ret;
+
+ valid_before = osf_uart->stream.stats.valid_frames;
+ ret = osf_stream_receive_bytes(&osf_uart->stream, buf, count);
+ stats = &osf_uart->stream.stats;
+
+ if (ret || stats->valid_frames != valid_before)
+ dev_dbg_ratelimited(&serdev->dev,
+ "rx count=%zu valid=%llu bad_magic=%llu bad_crc=%llu partial=%llu dropped=%llu ret=%d\n",
+ count, stats->valid_frames,
+ stats->bad_magic_resyncs,
+ stats->bad_crc_frames, stats->partial_frames,
+ stats->dropped_bytes, ret);
+
+ return count;
+}
+
+static const struct serdev_device_ops osf_serdev_ops = {
+ .receive_buf = osf_serdev_receive_buf,
+};
+
+static int osf_serdev_probe(struct serdev_device *serdev)
+{
+ struct device *dev = &serdev->dev;
+ struct osf_serdev *osf_uart;
+ unsigned int baudrate;
+ int ret;
+
+ osf_uart = devm_kzalloc(dev, sizeof(*osf_uart), GFP_KERNEL);
+ if (!osf_uart)
+ return -ENOMEM;
+
+ osf_uart->serdev = serdev;
+ osf_core_init(&osf_uart->osf, dev);
+ osf_stream_init(&osf_uart->stream, &osf_uart->osf);
+
+ serdev_device_set_drvdata(serdev, osf_uart);
+ serdev_device_set_client_ops(serdev, &osf_serdev_ops);
+
+ ret = devm_regulator_get_enable(dev, "vcc");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to enable vcc regulator\n");
+
+ ret = serdev_device_open(serdev);
+ if (ret)
+ return ret;
+
+ baudrate = serdev_device_set_baudrate(serdev, OSF_SERDEV_BAUD);
+ if (baudrate != OSF_SERDEV_BAUD)
+ dev_warn(dev, "requested %u baud, controller set %u\n",
+ OSF_SERDEV_BAUD, baudrate);
+
+ serdev_device_set_flow_control(serdev, false);
+
+ return 0;
+}
+
+static void osf_serdev_remove(struct serdev_device *serdev)
+{
+ struct osf_serdev *osf_uart = serdev_device_get_drvdata(serdev);
+
+ /* Stop the RX producer before unregistering IIO consumers. */
+ serdev_device_close(serdev);
+ osf_stream_reset(&osf_uart->stream);
+ osf_core_unregister_iio(&osf_uart->osf);
+}
+
+static const struct of_device_id osf_serdev_of_match[] = {
+ { .compatible = "opensensorfusion,osf" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, osf_serdev_of_match);
+
+static struct serdev_device_driver osf_serdev_driver = {
+ .probe = osf_serdev_probe,
+ .remove = osf_serdev_remove,
+ .driver = {
+ .name = "open-sensor-fusion-uart",
+ .of_match_table = osf_serdev_of_match,
+ },
+};
+module_serdev_device_driver(osf_serdev_driver);
+
+MODULE_DESCRIPTION("Open Sensor Fusion IIO driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device
2026-06-28 19:13 ` [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device Jinseob Kim
@ 2026-06-28 19:19 ` sashiko-bot
2026-06-29 15:39 ` Conor Dooley
1 sibling, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-06-28 19:19 UTC (permalink / raw)
To: Jinseob Kim; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Using a generic protocol name as the sole compatible string instead of a specific product identity.
--
commit 52d695764bb9f94bbb11a6128ea968762ee2ceef
Author: Jinseob Kim <kimjinseob88@gmail.com>
dt-bindings: iio: add Open Sensor Fusion device
This commit adds a binding for the generic Open Sensor Fusion host interface.
Sensor channels and protocol versions are discovered dynamically at runtime,
so they are not described individually in the Device Tree.
> diff --git a/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
> new file mode 100644
> index 0000000000000..8016d582fd970
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
[ ... ]
> +properties:
> + compatible:
> + const: opensensorfusion,osf
[Severity: Medium]
Does this generic compatible string prevent the kernel from applying future
quirks or workarounds if a specific board revision or hardware variant has
silicon bugs or unique power sequencing requirements?
The commit message mentions that product identities are explicitly not used
as the compatible string. By defining the generic protocol name as the only
valid value, the kernel lacks the ability to distinguish between different
hardware implementations that might need specific handling.
Would it be more appropriate to allow or require a hardware-specific
compatible string (such as the OSF Green product identity) alongside the
generic fallback?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260628191337.937-1-kimjinseob88@gmail.com?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 5/5] iio: osf: add UART IIO driver
2026-06-28 19:13 ` [PATCH RFC v6 5/5] iio: osf: add UART IIO driver Jinseob Kim
@ 2026-06-28 19:26 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-06-28 19:26 UTC (permalink / raw)
To: Jinseob Kim; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Propagating application-level errors corrupts the UART transport stream state machine. In `osf_stream_process()`, if `osf_core_receive_frame()` returns any error, the code assumes the frame length is untrusted, drops only 1 byte, and forces a stream resynchronization. However, `osf_core_receive_frame()` returns errors for valid, successfully decoded frames under application-level failures, such as `-EOPNOTSUPP` for unsupported frame types, or errors from IIO buffer pushes (e.g., in `osf_iio_push_sample()`). Treating these application-layer errors as framing errors causes the driver to drop the first byte of a perfectly valid frame, destroying the UART parser's synchronization and causing it to discard the rest of the frame and potentially subsequent frames.
--
commit ecab881e8156b9200eed2042dbafce633317b27f
Author: Jinseob Kim <kimjinseob88@gmail.com>
iio: osf: add UART IIO driver
Add the Open Sensor Fusion serdev transport, driver core, and IIO
registration path as one complete driver patch.
> diff --git a/drivers/iio/opensensorfusion/osf_core.c b/drivers/iio/opensensorfusion/osf_core.c
> new file mode 100644
> index 0000000000000..207de03dbcdef
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_core.c
[ ... ]
> +int osf_core_receive_frame(struct osf_device *osf, const u8 *buf, size_t len)
> +{
> + struct osf_frame frame;
> + size_t frame_len;
> + int ret;
> +
> + ret = osf_protocol_decode_frame(buf, len, &frame, &frame_len);
> + if (ret)
> + return ret;
> +
> + if (frame_len != len)
> + return -EMSGSIZE;
> +
> + switch (frame.message_type) {
> + case OSF_MSG_SENSOR_SAMPLE:
> + return osf_core_handle_sensor_sample(osf, &frame);
> + case OSF_MSG_DEVICE_STATUS:
> + return osf_core_handle_device_status(osf, &frame);
> + case OSF_MSG_CAPABILITY_REPORT:
> + return osf_core_handle_capability_report(osf, &frame);
> + default:
> + if (frame.message_type >= OSF_RESERVED_MSG_FIRST &&
> + frame.message_type <= OSF_RESERVED_MSG_LAST)
> + return 0;
> + if (frame.message_type >= OSF_VENDOR_PRIVATE_FIRST)
> + return 0;
> + return -EOPNOTSUPP;
[Severity: High]
Will returning an application-level error like -EOPNOTSUPP here corrupt the
UART transport stream state machine?
If osf_core_receive_frame() returns an error for a validly framed but
unsupported message type, osf_stream_process() appears to treat it as a
framing error:
osf_stream_process() {
...
ret = osf_core_receive_frame(stream->osf, stream->buf, frame_len);
if (ret) {
...
stream->stats.dropped_bytes++;
osf_stream_drop_invalid_head(stream);
continue;
}
}
By dropping 1 byte instead of consuming the full frame_len, the transport
state loses synchronization. This will likely cause the rest of the valid
frame and potentially subsequent frames to be dropped while it attempts to
resynchronize.
Should application-layer failures (like unsupported message types or failing
IIO buffer pushes) be absorbed and return 0 here to ensure the full frame
is consumed?
> + }
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260628191337.937-1-kimjinseob88@gmail.com?part=5
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser
2026-06-28 19:13 ` [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser Jinseob Kim
@ 2026-06-28 19:26 ` sashiko-bot
2026-06-29 14:10 ` Andy Shevchenko
1 sibling, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-06-28 19:26 UTC (permalink / raw)
To: Jinseob Kim; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Frame Smuggling / Unauthenticated Injection due to dropping only 1 byte on application-level error.
- [Low] The `partial_frames` statistic is defined but never updated.
--
commit c420661e9f0f330fb78aaadf3e5695f6b7ee7947
Author: Jinseob Kim <kimjinseob88@gmail.com>
iio: osf: add authenticated stream parser
Add a UART byte-stream parser for Open Sensor Fusion frames.
The parser searches for the OSF0 wire magic, keeps partial frames
buffered, checks header length and payload bounds, and passes complete
candidate frames to the core decoder.
> diff --git a/drivers/iio/opensensorfusion/osf_stream.c b/drivers/iio/opensensorfusion/osf_stream.c
> new file mode 100644
> index 0000000000000..470b4ec1f1370
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_stream.c
> @@ -0,0 +1,189 @@
[ ... ]
> + frame_len = OSF_FRAME_HEADER_LEN + payload_len + OSF_FRAME_CRC_LEN;
> + if (stream->len < frame_len)
> + break;
[Severity: Low]
Does this code miss updating the partial_frames statistic?
When the stream parser encounters a partial frame here and breaks out of the
processing loop, it appears stream->stats.partial_frames is not incremented.
This will leave it reporting 0 in debug outputs.
> +
> + ret = osf_core_receive_frame(stream->osf, stream->buf, frame_len);
> + if (ret) {
> + if (ret == -EBADMSG)
> + stream->stats.bad_crc_frames++;
> +
> + /*
> + * Until the decoder accepts the frame, payload_len is
> + * untrusted. Drop only the current head and resynchronize.
> + */
> + stream->stats.dropped_bytes++;
> + osf_stream_drop_invalid_head(stream);
[Severity: High]
Can this lead to an unauthenticated protocol injection if an application-level
handler rejects a valid frame?
If a legitimate frame has a valid CRC but osf_core_receive_frame() returns an
error (like -EPROTO or -EOPNOTSUPP) because the payload is rejected by a
handler, this path drops only the first byte of the outer frame rather than
discarding frame_len bytes.
Could this allow an attacker to embed fake OSF frames within the payload of a
legitimate sensor frame, which would then be parsed as a new frame after the
single-byte drop resynchronizes?
> + if (!first_err)
> + first_err = ret;
> + continue;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260628191337.937-1-kimjinseob88@gmail.com?part=4
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 3/5] iio: osf: add protocol decoding
2026-06-28 19:13 ` [PATCH RFC v6 3/5] iio: osf: add protocol decoding Jinseob Kim
@ 2026-06-29 14:05 ` Andy Shevchenko
0 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2026-06-29 14:05 UTC (permalink / raw)
To: Jinseob Kim
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, linux-iio, devicetree, linux-doc, linux-kernel
On Mon, Jun 29, 2026 at 04:13:35AM +0900, Jinseob Kim wrote:
> Add helpers for decoding Open Sensor Fusion frame headers and supported
> message payloads.
>
> The decoder validates the OSF0 wire magic, protocol major version,
> header length, payload bounds, reserved fields and CRC before exposing
> decoded frame contents to the rest of the driver.
>
> Use explicit little-endian wire storage sizes and designated
> initializers for decoded output structures.
...
> +#include <linux/bits.h>
> +#include <linux/crc32.h>
> +#include <linux/errno.h>
> +#include <linux/limits.h>
> +#include <linux/types.h>
> +#include <linux/unaligned.h>
...
> +#define OSF_FRAME_MAGIC 0x3046534f /* "OSF0" little-endian */
#define OSF_FRAME_MAGIC 0x3046534f /* "OSF0", little-endian */
(mind a comma).
...
> +int osf_protocol_decode_sensor_sample(const struct osf_frame *frame,
> + struct osf_sensor_sample *sample)
> +{
> + u16 channel_count;
> + u16 sample_format;
> + u16 sensor_type;
> + size_t expected_len;
> + const u8 *payload;
> +
> + if (!frame || !sample || !frame->payload)
> + return -EINVAL;
> +
> + if (frame->message_type != OSF_MSG_SENSOR_SAMPLE)
> + return -EPROTO;
> +
> + if (frame->payload_len < OSF_SENSOR_SAMPLE_BASE_LEN)
> + return -EMSGSIZE;
> +
> + payload = frame->payload;
> + sensor_type = get_unaligned_le16(payload);
> + channel_count = get_unaligned_le16(payload + 4);
> + sample_format = get_unaligned_le16(payload + 6);
> +
> + if (!osf_sensor_type_valid(sensor_type))
> + return -EPROTO;
> +
> + if (!channel_count)
> + return -EPROTO;
> +
> + if (sample_format != OSF_SAMPLE_FORMAT_S32)
> + return -EPROTO;
> +
> + if (get_unaligned_le32(payload + 12))
> + return -EPROTO;
> + if (channel_count > (SIZE_MAX - OSF_SENSOR_SAMPLE_BASE_LEN) /
> + sizeof(__le32))
> + return -EOVERFLOW;
Dead code because it's always 'false'? Hasn't compiler given a warning?
Always compile your code with `make W=1` using both compilers: clang and GCC.
> + expected_len = OSF_SENSOR_SAMPLE_BASE_LEN + channel_count * sizeof(__le32);
> + if (frame->payload_len != expected_len)
> + return -EMSGSIZE;
> +
> + *sample = (struct osf_sensor_sample) {
> + .sensor_type = sensor_type,
> + .sensor_index = get_unaligned_le16(payload + 2),
> + .channel_count = channel_count,
> + .sample_format = sample_format,
> + .scale_nano = get_unaligned_le32(payload + 8),
> + .samples = payload + OSF_SENSOR_SAMPLE_BASE_LEN,
> + };
> +
> + return 0;
> +}
...
> + if (capability_count > (SIZE_MAX - OSF_CAP_REPORT_BASE_LEN) /
> + OSF_CAP_SENSOR_ENTRY_LEN)
> + return -EOVERFLOW;
Ditto.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
` (4 preceding siblings ...)
2026-06-28 19:13 ` [PATCH RFC v6 5/5] iio: osf: add UART IIO driver Jinseob Kim
@ 2026-06-29 14:09 ` Andy Shevchenko
2026-06-29 14:12 ` Andy Shevchenko
2026-06-29 15:25 ` David Lechner
6 siblings, 1 reply; 16+ messages in thread
From: Andy Shevchenko @ 2026-06-29 14:09 UTC (permalink / raw)
To: Jinseob Kim
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, linux-iio, devicetree, linux-doc, linux-kernel
On Mon, Jun 29, 2026 at 04:13:32AM +0900, Jinseob Kim wrote:
> Open Sensor Fusion (OSF) devices expose a UART/serdev host interface
> for a sensor aggregation hub. This RFC adds a Linux IIO driver that
> parses OSF frames and creates IIO devices at runtime from capability
> reports provided by the device firmware.
>
> When the corresponding capabilities are reported, the driver exposes
> accelerometer, gyroscope, magnetometer, and temperature data as IIO
> devices named osf-accel, osf-gyro, osf-magn, and osf-temp.
>
> This remains RFC while the binding, protocol subset, runtime discovery
> model, and driver-facing ABI are reviewed.
Where are the lore links to the previous versions?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser
2026-06-28 19:13 ` [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser Jinseob Kim
2026-06-28 19:26 ` sashiko-bot
@ 2026-06-29 14:10 ` Andy Shevchenko
1 sibling, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2026-06-29 14:10 UTC (permalink / raw)
To: Jinseob Kim
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, linux-iio, devicetree, linux-doc, linux-kernel
On Mon, Jun 29, 2026 at 04:13:36AM +0900, Jinseob Kim wrote:
> Add a UART byte-stream parser for Open Sensor Fusion frames.
>
> The parser searches for the OSF0 wire magic, keeps partial frames
> buffered, checks header length and payload bounds, and passes complete
> candidate frames to the core decoder.
>
> Rejected candidate frames drop only the current head byte before
> resynchronizing, so a corrupted unauthenticated payload length cannot
> make the parser skip later valid frames.
...
> +#define OSF_STREAM_MAGIC_LEN 4
> +#define OSF_STREAM_MAX_PAYLOAD_LEN \
> + (OSF_STREAM_MAX_FRAME_LEN - OSF_FRAME_HEADER_LEN - OSF_FRAME_CRC_LEN)
> +
> +static const u8 osf_stream_magic[OSF_STREAM_MAGIC_LEN] = {
> + 'O', 'S', 'F', '0',
> +};
You have already this in the header (as FourCC), use that.
...
> +static size_t osf_stream_discard_to_magic(struct osf_stream *stream)
> +{
> + size_t old_len = stream->len;
> + size_t match_len;
> + size_t i;
> +
> + for (i = 0; i < stream->len; i++) {
for (size_t i = 0; i < stream->len; i++) {
> + match_len = stream->len - i;
> + if (match_len > OSF_STREAM_MAGIC_LEN)
> + match_len = OSF_STREAM_MAGIC_LEN;
> +
> + if (osf_stream_magic_match(stream->buf + i, match_len)) {
> + if (i)
> + osf_stream_discard(stream, i);
> + return i;
> + }
> + }
> +
> + stream->len = 0;
> + return old_len;
> +}
...
I stop here, because it's obvious that you neglected and ignored my previous
reviews. No explanation given, nothing. This is not how you should interact
with the community.
Come again when each of the given comment will be either addressed or argued.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver
2026-06-29 14:09 ` [PATCH RFC v6 0/5] iio: add Open Sensor Fusion " Andy Shevchenko
@ 2026-06-29 14:12 ` Andy Shevchenko
0 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2026-06-29 14:12 UTC (permalink / raw)
To: Jinseob Kim
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, linux-iio, devicetree, linux-doc, linux-kernel
On Mon, Jun 29, 2026 at 05:09:21PM +0300, Andy Shevchenko wrote:
> On Mon, Jun 29, 2026 at 04:13:32AM +0900, Jinseob Kim wrote:
> > Open Sensor Fusion (OSF) devices expose a UART/serdev host interface
> > for a sensor aggregation hub. This RFC adds a Linux IIO driver that
> > parses OSF frames and creates IIO devices at runtime from capability
> > reports provided by the device firmware.
> >
> > When the corresponding capabilities are reported, the driver exposes
> > accelerometer, gyroscope, magnetometer, and temperature data as IIO
> > devices named osf-accel, osf-gyro, osf-magn, and osf-temp.
> >
> > This remains RFC while the binding, protocol subset, runtime discovery
> > model, and driver-facing ABI are reviewed.
>
> Where are the lore links to the previous versions?
Besides that you utterly ignorant in replying to the comments of the reviewers.
v3 and v5 left unanswered, third time in this version I give the very same
comments. What the heck?!
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
` (5 preceding siblings ...)
2026-06-29 14:09 ` [PATCH RFC v6 0/5] iio: add Open Sensor Fusion " Andy Shevchenko
@ 2026-06-29 15:25 ` David Lechner
2026-06-29 16:47 ` Kim Jinseob
6 siblings, 1 reply; 16+ messages in thread
From: David Lechner @ 2026-06-29 15:25 UTC (permalink / raw)
To: Jinseob Kim, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Nuno Sá, Andy Shevchenko, Jonathan Corbet, Shuah Khan,
linux-iio, devicetree, linux-doc, linux-kernel
On 6/28/26 2:13 PM, Jinseob Kim wrote:
> Open Sensor Fusion (OSF) devices expose a UART/serdev host interface
> for a sensor aggregation hub. This RFC adds a Linux IIO driver that
> parses OSF frames and creates IIO devices at runtime from capability
> reports provided by the device firmware.
>
> When the corresponding capabilities are reported, the driver exposes
> accelerometer, gyroscope, magnetometer, and temperature data as IIO
> devices named osf-accel, osf-gyro, osf-magn, and osf-temp.
>
> This remains RFC while the binding, protocol subset, runtime discovery
> model, and driver-facing ABI are reviewed.
If you are just looking for review and don't have specific questions,
then it is time to drop the RFC.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device
2026-06-28 19:13 ` [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device Jinseob Kim
2026-06-28 19:19 ` sashiko-bot
@ 2026-06-29 15:39 ` Conor Dooley
1 sibling, 0 replies; 16+ messages in thread
From: Conor Dooley @ 2026-06-29 15:39 UTC (permalink / raw)
To: Jinseob Kim
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, linux-iio, devicetree, linux-doc, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 4454 bytes --]
On Mon, Jun 29, 2026 at 04:13:33AM +0900, Jinseob Kim wrote:
> Add a binding for the generic Open Sensor Fusion host interface.
>
> Open Sensor Fusion devices report capabilities and samples over an OSF
> protocol stream. Sensor channels are discovered at runtime from
> capability reports instead of being described individually in Device
> Tree.
>
> The protocol version is discovered at runtime from the OSF frame header.
> OSF GREEN is a product identity, and OSF0 is a wire-format magic value,
> so neither is used as the Linux compatible string.
>
> Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
> ---
> .../bindings/iio/opensensorfusion,osf.yaml | 54 +++++++++++++++++++
> .../devicetree/bindings/vendor-prefixes.yaml | 2 +
> MAINTAINERS | 6 +++
> 3 files changed, 62 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
>
> diff --git a/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
> new file mode 100644
> index 000000000..8016d582f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/opensensorfusion,osf.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Open Sensor Fusion Sensor Aggregation Hub
> +
> +maintainers:
> + - Jinseob Kim <kimjinseob88@gmail.com>
> +
> +description: |
> + This binding documents the generic Open Sensor Fusion host interface. Open
> + Sensor Fusion is a sensor aggregation hub. The hub exposes an OSF protocol
> + data stream over its host interface and reports capabilities and samples for
> + multiple sensor classes. The actual sensor channels are discovered at runtime
> + from OSF capability reports instead of describing them in Device Tree. The
> + protocol version is discovered at runtime.
> +
> + Public project documentation is available at:
> +
> + https://github.com/opensensorfusion
> +
> + The compatible describes the generic Open Sensor Fusion host interface.
> It
> + is not an OSF GREEN board identity, and it does not encode the OSF0 wire
> + magic.
I think this is evident from the previous text, and the first part is a
bit confusing while the latter half is a bit confusing.
Just remove this sentence I think.
Binding looks fine to me, I'll provide a r-b when you submit a non-RFC
version.
pw-bot: not-applicable
Thanks,
Conor.
> OSF0, protocol_major, and protocol_minor are wire-protocol details
> + exchanged in OSF frames.
> +
> +allOf:
> + - $ref: /schemas/serial/serial-peripheral-props.yaml#
> +
> +properties:
> + compatible:
> + const: opensensorfusion,osf
> +
> + vcc-supply:
> + description:
> + Regulator supplying power to the Open Sensor Fusion device.
> +
> +required:
> + - compatible
> + - vcc-supply
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + serial {
> + sensor {
> + compatible = "opensensorfusion,osf";
> + vcc-supply = <&vcc_sensor>;
> + };
> + };
> +...
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index 28784d66a..88172d4a4 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -1237,6 +1237,8 @@ patternProperties:
> description: OpenPandora GmbH
> "^openrisc,.*":
> description: OpenRISC.io
> + "^opensensorfusion,.*":
> + description: Open Sensor Fusion
> "^openwrt,.*":
> description: OpenWrt
> "^option,.*":
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c2c6d7927..e4df9d8dc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -20011,6 +20011,12 @@ F: Documentation/devicetree/
> F: arch/*/boot/dts/
> F: include/dt-bindings/
>
> +OPEN SENSOR FUSION
> +M: Jinseob Kim <kimjinseob88@gmail.com>
> +S: Maintained
> +F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
> +K: opensensorfusion
> +
> OPENCOMPUTE PTP CLOCK DRIVER
> M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
> L: netdev@vger.kernel.org
> --
> 2.43.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver
2026-06-29 15:25 ` David Lechner
@ 2026-06-29 16:47 ` Kim Jinseob
0 siblings, 0 replies; 16+ messages in thread
From: Kim Jinseob @ 2026-06-29 16:47 UTC (permalink / raw)
To: David Lechner
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Nuno Sá, Andy Shevchenko, Jonathan Corbet, Shuah Khan,
linux-iio, devicetree, linux-doc, linux-kernel
Andy, you are right. I should have included the previous-version links in the
cover letter.
I also did not consistently track and answer all review comments across
revisions. I carried several comments into later revisions, but that was not
sufficient. I should have made sure every reviewer comment was either
addressed in the code or explicitly answered before posting the next revision.
Sorry for that.
For reference, the earlier public versions are:
v1:
https://lore.kernel.org/r/20260520072843.3593-1-kimjinseob88@gmail.com
v2:
https://lore.kernel.org/r/20260524085312.15369-1-kimjinseob88@gmail.com
v3:
https://lore.kernel.org/r/20260529121005.1470-1-kimjinseob88@gmail.com
v4:
https://lore.kernel.org/r/20260607234343.22109-1-kimjinseob88@gmail.com
v5:
https://lore.kernel.org/r/20260616072242.3942-1-kimjinseob88@gmail.com
v6:
https://lore.kernel.org/r/20260628191337.937-1-kimjinseob88@gmail.com
David, understood. If the next revision is just asking for normal review and
I do not have specific open questions, I will drop the RFC tag. If I still
mark it RFC, I will state the specific questions clearly in the cover letter.
I will not post another revision until I have gone through the previous
review comments and made sure each one is either addressed in the code or
explicitly answered. I will also include the previous-version links in the
next cover letter.
Thanks
Jinseob
2026년 6월 30일 (화) 오전 12:25, David Lechner <dlechner@baylibre.com>님이 작성:
>
> On 6/28/26 2:13 PM, Jinseob Kim wrote:
> > Open Sensor Fusion (OSF) devices expose a UART/serdev host interface
> > for a sensor aggregation hub. This RFC adds a Linux IIO driver that
> > parses OSF frames and creates IIO devices at runtime from capability
> > reports provided by the device firmware.
> >
> > When the corresponding capabilities are reported, the driver exposes
> > accelerometer, gyroscope, magnetometer, and temperature data as IIO
> > devices named osf-accel, osf-gyro, osf-magn, and osf-temp.
> >
> > This remains RFC while the binding, protocol subset, runtime discovery
> > model, and driver-facing ABI are reviewed.
>
> If you are just looking for review and don't have specific questions,
> then it is time to drop the RFC.
>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-06-29 16:47 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-28 19:13 [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device Jinseob Kim
2026-06-28 19:19 ` sashiko-bot
2026-06-29 15:39 ` Conor Dooley
2026-06-28 19:13 ` [PATCH RFC v6 2/5] Documentation: iio: add Open Sensor Fusion driver overview Jinseob Kim
2026-06-28 19:13 ` [PATCH RFC v6 3/5] iio: osf: add protocol decoding Jinseob Kim
2026-06-29 14:05 ` Andy Shevchenko
2026-06-28 19:13 ` [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser Jinseob Kim
2026-06-28 19:26 ` sashiko-bot
2026-06-29 14:10 ` Andy Shevchenko
2026-06-28 19:13 ` [PATCH RFC v6 5/5] iio: osf: add UART IIO driver Jinseob Kim
2026-06-28 19:26 ` sashiko-bot
2026-06-29 14:09 ` [PATCH RFC v6 0/5] iio: add Open Sensor Fusion " Andy Shevchenko
2026-06-29 14:12 ` Andy Shevchenko
2026-06-29 15:25 ` David Lechner
2026-06-29 16:47 ` Kim Jinseob
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox