From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f42.google.com (mail-pj1-f42.google.com [209.85.216.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6DE3E3E1681 for ; Fri, 29 May 2026 12:11:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.42 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780056666; cv=none; b=MonYsiVMn5idpwpaLhJu2X/vh1FhS1+qYH8OjJgEGDHVYRKdll1Aks+5cpUHIhgNH1TEkwqzkkHCHyl8+dflSdJ1onJRT6le+jaZUISu8iq3T2s6bETtLnQCLb4ILcs1K8y83AP3+khGcKHVPN9RaYFjXzixiHMp03T16aiQmgw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780056666; c=relaxed/simple; bh=c6/Aiu4UZ/sU0uPkdJkuopnm1atE3NwBxxm+EVVTIYE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bVvpkmbTUMUx8aShjr5iyfEuoHyW8oubnew1/fL7h61tKHp4hnvng/JuOgniEA9X4TifbMnAIYK6C4w82H+1gOCStX6npZAvF53MQyXtlMqYS2OkO6KtZ21BjeHWpPxns0KE02UeG46hD22bzLD0LKOe1nNem3mNbPgTTDZzrzU= 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=LfUcR+AH; arc=none smtp.client-ip=209.85.216.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LfUcR+AH" Received: by mail-pj1-f42.google.com with SMTP id 98e67ed59e1d1-36bdb11bf8bso131815a91.0 for ; Fri, 29 May 2026 05:11:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780056664; x=1780661464; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JQCaoukUuAifdwoQLb2AtvzNeKZEcEahL4zcCl7ipLA=; b=LfUcR+AH8z20kY8dSPn9thJvvthOcAFZu8mX0esWy5VP23TxxSMg8jUXTgKvcTkZcn MGISgvPdhTqpZ/Mb2s4GiG03lttSmj2Cr2z/kS4U3IQXIOTQm/nQqR19dzJJSG3hRWjI YiDndByAm6AVdp7tZOVGf5g1j7zQljmc5lREVkqM8gYvGMwQMuDqPKcA/qjoQMj7VRE2 ynHnsJq2+XFpqlPASO8CIHlXe9Z/T5c+w0q02VCz6NI9e12tFFm3ipesFp5/YoTxLKXu 9N+ZZRO6itO512x780DYhpQjRgzcfFkPO3XDrBcpdr9MpNDtnb4SZamZd9W5JnAZinbl KVVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780056664; x=1780661464; 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; bh=JQCaoukUuAifdwoQLb2AtvzNeKZEcEahL4zcCl7ipLA=; b=dSJZDB83AQi+B7vU07WpOKF25XnbmqxC+uDfLDUK7XgcNzTiVRwLwQzsIb8xst3bNo SgREgvvupbWNKwvZc8c0HoHsBg6dsDV15VliUfWmCBv7qvUyRWCwd97cuvpkmzONOXJQ kcYsu67rM1WBcDaO1jyI+6gSW1cDgZG0icpMCtZl3RHXo3YO4PQjJku9PZuKu3bFtS6E 9io1+5qvRQ62I5UPyeRfeQBEJyZzPy/hFuoF3bAbw/nhea9XqcNGRtRgwto1fzwcQhOa 8VjGr39vtzASLeZcDlE177eenXHr7RjSYBmiMynabTfCFcG7gXfvWI/+og/0BwNQHPit 1SQQ== X-Forwarded-Encrypted: i=1; AFNElJ+pIRzqvRDaWNTv8lcsI86r0T24DGhDBMKaPSV88Dcw05N7EmYQokEP/JSqtwrsm6Xq2Y7YCN7TROjvwjA=@vger.kernel.org X-Gm-Message-State: AOJu0YwSjhN+QikF3NFlRPJDwKsNqeMkM4POmtHZIq33v06G9boq4yb+ e6mm10QlwCfb8TxXCg1iJeuXjq/6jRfiEIS5lWtufIHLmrvQTjAPTySgzVchFKUk6vM= X-Gm-Gg: Acq92OEldZHI49h+6C7ijZfLmCHvsnqKH5dPwqWiWejZfQvI3u8Sundmc6XHx1eVJum Gl8paZ12fxi1xqlkMBpWs97uj48+bYNdisQhU+10i0gCITWWAzBMNyKTong0Bgask7hwFevd2ri rpJPdHR17dBweLe1SpyksJmx5nsGVFOAYgwpYO3qZZYzcJ2r6fWrXxpPAABe6WIJuTfrJRIt0Qj ezCaqdlSoD6jHo5t+Hva/rTgJeG855NPAc8DvUp+CJ29Yw440Ecf+XpL8jDi4UM6h9VnpZQE4qZ FVGUYf+93GjS0yMX6BJA5cr9iFu9gHi4A3nZHgBUvYhCeYIQfrqa34fp2dIptkKwPPlXIsQIGp2 D5VqqK9f/T3LQCclDI+zEZWqeYTGk6d9/v2kFe7uiya5QJ4cO/AU/ypohA1o8nqvz2wRTVZSZvr hWYakoJsAWtjSn11AI63FFcR5YtdY/QivM15cWm+9k1iseSOH8qt2OoGhJjaf6B3kXsWuM6NWVj 2b3K6Dp1C8koSEjfApvcYJaLOt8KNf5lepkfy7hwVCaymu2kIfYN81uox4= X-Received: by 2002:a17:90a:ec88:b0:369:7421:b36f with SMTP id 98e67ed59e1d1-36bbceae629mr3232957a91.21.1780056663735; Fri, 29 May 2026 05:11:03 -0700 (PDT) Received: from DESKTOP-G3E0OSP.localdomain ([112.172.255.242]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-36bbdf3afc6sm942820a91.7.2026.05.29.05.11.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 May 2026 05:11:03 -0700 (PDT) From: Jinseob Kim To: Jonathan Cameron , linux-iio@vger.kernel.org Cc: David Lechner , Nuno Sa , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RFC v3 5/6] iio: osf: add UART serdev transport Date: Fri, 29 May 2026 21:10:04 +0900 Message-ID: <20260529121005.1470-6-kimjinseob88@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260529121005.1470-1-kimjinseob88@gmail.com> References: <20260529121005.1470-1-kimjinseob88@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: 8bit Register the OSF serdev driver. Pass received bytes into the OSF0 stream parser. Signed-off-by: Jinseob Kim --- MAINTAINERS | 4 + drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/opensensorfusion/Kconfig | 15 +++ drivers/iio/opensensorfusion/Makefile | 5 + drivers/iio/opensensorfusion/osf_core.c | 107 +++++++++++++++++++++ drivers/iio/opensensorfusion/osf_core.h | 18 ++++ drivers/iio/opensensorfusion/osf_serdev.c | 111 ++++++++++++++++++++++ 8 files changed, 262 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_serdev.c diff --git a/MAINTAINERS b/MAINTAINERS index 91c342d88..ebbd82bf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19982,7 +19982,11 @@ M: Jinseob Kim S: Maintained F: Documentation/devicetree/bindings/iio/imu/opensensorfusion,osf-green.yaml F: Documentation/iio/open-sensor-fusion-protocol-v0.rst +F: drivers/iio/opensensorfusion/Kconfig +F: drivers/iio/opensensorfusion/Makefile +F: drivers/iio/opensensorfusion/osf_core.* F: drivers/iio/opensensorfusion/osf_protocol.* +F: drivers/iio/opensensorfusion/osf_serdev.c F: drivers/iio/opensensorfusion/osf_stream.* OPEN FIRMWARE AND FLATTENED DEVICE TREE 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..360f25b4f --- /dev/null +++ b/drivers/iio/opensensorfusion/Kconfig @@ -0,0 +1,15 @@ +# 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 + help + Build the Open Sensor Fusion UART receive path. + + The driver receives OSF0 frames over a serdev UART. + Frames are decoded and validated before being passed to the + driver core. + This patch only adds the transport path. + IIO device registration is added separately. diff --git a/drivers/iio/opensensorfusion/Makefile b/drivers/iio/opensensorfusion/Makefile new file mode 100644 index 000000000..940c82edd --- /dev/null +++ b/drivers/iio/opensensorfusion/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_OPEN_SENSOR_FUSION) += open-sensor-fusion.o + +open-sensor-fusion-y := osf_core.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..c867b3158 --- /dev/null +++ b/drivers/iio/opensensorfusion/osf_core.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include + +#include "osf_core.h" +#include "osf_protocol.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) +{ + memset(osf, 0, sizeof(*osf)); + osf->dev = dev; +} + +void osf_core_unregister_iio(struct osf_device *osf) +{ +} + +static int osf_core_validate_sensor_sample(const struct osf_frame *frame) +{ + struct osf_sensor_sample sample; + + return osf_protocol_decode_sensor_sample(frame, &sample); +} + +static int osf_core_validate_device_status(const struct osf_frame *frame) +{ + struct osf_device_status status; + int ret; + + ret = osf_protocol_decode_device_status(frame, &status); + if (ret) + return ret; + + if (status.reserved) + return -EPROTO; + + return 0; +} + +static int osf_core_validate_capability_report(const struct osf_frame *frame) +{ + struct osf_capability_entry entry; + struct osf_capability_report report; + unsigned int i; + int ret; + + ret = osf_protocol_decode_capability_report(frame, &report); + if (ret) + return ret; + + for (i = 0; i < report.capability_count; i++) { + ret = osf_protocol_decode_capability_entry(&report, i, &entry); + if (ret) + return ret; + } + + 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; + + if (!osf || !buf) + return -EINVAL; + + 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: + ret = osf_core_validate_sensor_sample(&frame); + break; + case OSF_MSG_DEVICE_STATUS: + ret = osf_core_validate_device_status(&frame); + break; + case OSF_MSG_CAPABILITY_REPORT: + ret = osf_core_validate_capability_report(&frame); + break; + default: + if (frame.message_type >= OSF_RESERVED_MSG_FIRST && + frame.message_type <= OSF_RESERVED_MSG_LAST) + ret = 0; + else if (frame.message_type >= OSF_VENDOR_PRIVATE_FIRST) + ret = 0; + else + ret = -EOPNOTSUPP; + break; + } + + if (!ret) + osf->last_sequence = frame.sequence; + + return ret; +} diff --git a/drivers/iio/opensensorfusion/osf_core.h b/drivers/iio/opensensorfusion/osf_core.h new file mode 100644 index 000000000..3680c8c9b --- /dev/null +++ b/drivers/iio/opensensorfusion/osf_core.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _OSF_CORE_H +#define _OSF_CORE_H + +#include + +struct device; + +struct osf_device { + struct device *dev; + 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); + +#endif diff --git a/drivers/iio/opensensorfusion/osf_serdev.c b/drivers/iio/opensensorfusion/osf_serdev.c new file mode 100644 index 000000000..1ac93548d --- /dev/null +++ b/drivers/iio/opensensorfusion/osf_serdev.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +#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, + (unsigned long long)stats->valid_frames, + (unsigned long long)stats->bad_magic_resyncs, + (unsigned long long)stats->bad_crc_frames, + (unsigned long long)stats->partial_frames, + (unsigned long long)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 osf_serdev *osf_uart; + unsigned int baudrate; + int ret; + + osf_uart = devm_kzalloc(&serdev->dev, sizeof(*osf_uart), GFP_KERNEL); + if (!osf_uart) + return -ENOMEM; + + osf_uart->serdev = serdev; + osf_core_init(&osf_uart->osf, &serdev->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 = serdev_device_open(serdev); + if (ret) + return ret; + + baudrate = serdev_device_set_baudrate(serdev, OSF_SERDEV_BAUD); + if (baudrate != OSF_SERDEV_BAUD) + dev_warn(&serdev->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); + + 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-green" }, + { } +}; +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