[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250512012748.79749-16-damien.riegel@silabs.com>
Date: Sun, 11 May 2025 21:27:48 -0400
From: Damien Riégel <damien.riegel@...abs.com>
To: Andrew Lunn <andrew+netdev@...n.ch>,
"David S . Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>, Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Silicon Labs Kernel Team <linux-devel@...abs.com>,
netdev@...r.kernel.org, devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [RFC net-next 15/15] net: cpc: add Bluetooth HCI driver
Add support for Bluetooth HCI driver. As most of the protocol is already
handled by the remote endpoint, this driver is just doing some glue to
plug into CPC.
Signed-off-by: Damien Riégel <damien.riegel@...abs.com>
---
drivers/net/cpc/Kconfig | 2 +-
drivers/net/cpc/Makefile | 2 +-
drivers/net/cpc/ble.c | 147 +++++++++++++++++++++++++++++++++++++++
drivers/net/cpc/ble.h | 14 ++++
drivers/net/cpc/main.c | 23 ++++--
5 files changed, 181 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/cpc/ble.c
create mode 100644 drivers/net/cpc/ble.h
diff --git a/drivers/net/cpc/Kconfig b/drivers/net/cpc/Kconfig
index f5159390a82..e8faa351bf7 100644
--- a/drivers/net/cpc/Kconfig
+++ b/drivers/net/cpc/Kconfig
@@ -2,7 +2,7 @@
menuconfig CPC
tristate "Silicon Labs Co-Processor Communication (CPC) Protocol"
- depends on NET && SPI
+ depends on NET && SPI && BT
select CRC_ITU_T
help
Provide support for the CPC protocol to Silicon Labs EFR32 devices.
diff --git a/drivers/net/cpc/Makefile b/drivers/net/cpc/Makefile
index 195cdf4ad62..cee40aec412 100644
--- a/drivers/net/cpc/Makefile
+++ b/drivers/net/cpc/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-cpc-y := endpoint.o header.o interface.o main.o protocol.o spi.o system.o
+cpc-y := ble.o endpoint.o header.o interface.o main.o protocol.o spi.o system.o
obj-$(CONFIG_CPC) += cpc.o
diff --git a/drivers/net/cpc/ble.c b/drivers/net/cpc/ble.c
new file mode 100644
index 00000000000..2b7aec4dbdf
--- /dev/null
+++ b/drivers/net/cpc/ble.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Bluetooth HCI over CPC.
+ *
+ * Copyright (c) 2025, Silicon Laboratories, Inc.
+ */
+
+#include <linux/skbuff.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "ble.h"
+#include "cpc.h"
+
+struct cpc_ble {
+ struct cpc_endpoint *ep;
+ struct hci_dev *hdev;
+ struct sk_buff_head txq;
+};
+
+static int cpc_ble_open(struct hci_dev *hdev)
+{
+ struct cpc_ble *ble = hci_get_drvdata(hdev);
+
+ skb_queue_head_init(&ble->txq);
+
+ return cpc_endpoint_connect(ble->ep);
+}
+
+static int cpc_ble_close(struct hci_dev *hdev)
+{
+ struct cpc_ble *ble = hci_get_drvdata(hdev);
+
+ cpc_endpoint_disconnect(ble->ep);
+
+ skb_queue_purge(&ble->txq);
+
+ return 0;
+}
+
+static int cpc_ble_flush(struct hci_dev *hdev)
+{
+ struct cpc_ble *ble = hci_get_drvdata(hdev);
+
+ skb_queue_purge(&ble->txq);
+
+ return 0;
+}
+
+static int cpc_ble_send(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct cpc_ble *ble = hci_get_drvdata(hdev);
+
+ memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+
+ return cpc_endpoint_write(ble->ep, skb);
+}
+
+static void cpc_ble_rx_frame(struct cpc_endpoint *ep, struct sk_buff *skb)
+{
+ struct cpc_ble *ble = cpc_endpoint_get_drvdata(ep);
+
+ hci_skb_pkt_type(skb) = *((u8 *)skb_pull_data(skb, 1));
+ hci_skb_expect(skb) = skb->len;
+
+ hci_recv_frame(ble->hdev, skb);
+}
+
+static struct cpc_endpoint_ops cpc_ble_ops = {
+ .rx = cpc_ble_rx_frame,
+};
+
+static int cpc_ble_probe(struct cpc_endpoint *ep)
+{
+ struct cpc_ble *ble;
+ int err;
+
+ ble = kzalloc(sizeof(*ble), GFP_KERNEL);
+ if (!ble) {
+ err = -ENOMEM;
+ goto alloc_ble_fail;
+ }
+
+ cpc_endpoint_set_ops(ep, &cpc_ble_ops);
+ cpc_endpoint_set_drvdata(ep, ble);
+
+ ble->ep = ep;
+ ble->hdev = hci_alloc_dev();
+ if (!ble->hdev) {
+ err = -ENOMEM;
+ goto alloc_hdev_fail;
+ }
+
+ hci_set_drvdata(ble->hdev, ble);
+ ble->hdev->open = cpc_ble_open;
+ ble->hdev->close = cpc_ble_close;
+ ble->hdev->flush = cpc_ble_flush;
+ ble->hdev->send = cpc_ble_send;
+
+ err = hci_register_dev(ble->hdev);
+ if (err)
+ goto register_hdev_fail;
+
+ return 0;
+
+register_hdev_fail:
+ hci_free_dev(ble->hdev);
+alloc_hdev_fail:
+ kfree(ble);
+alloc_ble_fail:
+ return err;
+}
+
+static void cpc_ble_remove(struct cpc_endpoint *ep)
+{
+ struct cpc_ble *ble = cpc_endpoint_get_drvdata(ep);
+
+ hci_unregister_dev(ble->hdev);
+ hci_free_dev(ble->hdev);
+ kfree(ble);
+}
+
+static struct cpc_driver ble_driver = {
+ .driver = {
+ .name = CPC_BLUETOOTH_ENDPOINT_NAME,
+ },
+ .probe = cpc_ble_probe,
+ .remove = cpc_ble_remove,
+};
+
+/**
+ * cpc_ble_drv_register - Register the ble endpoint driver.
+ *
+ * @return: 0 on success, otherwise a negative error code.
+ */
+int cpc_ble_drv_register(void)
+{
+ return cpc_driver_register(&ble_driver);
+}
+
+/**
+ * cpc_ble_drv_unregister - Unregister the ble endpoint driver.
+ */
+void cpc_ble_drv_unregister(void)
+{
+ cpc_driver_unregister(&ble_driver);
+}
diff --git a/drivers/net/cpc/ble.h b/drivers/net/cpc/ble.h
new file mode 100644
index 00000000000..ae1cac4e7e8
--- /dev/null
+++ b/drivers/net/cpc/ble.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025, Silicon Laboratories, Inc.
+ */
+
+#ifndef __CPC_BLE_H
+#define __CPC_BLE_H
+
+#define CPC_BLUETOOTH_ENDPOINT_NAME "silabs,cpc-ble"
+
+int cpc_ble_drv_register(void);
+void cpc_ble_drv_unregister(void);
+
+#endif
diff --git a/drivers/net/cpc/main.c b/drivers/net/cpc/main.c
index b4e73145ac2..e5636207d5d 100644
--- a/drivers/net/cpc/main.c
+++ b/drivers/net/cpc/main.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include "cpc.h"
+#include "ble.h"
#include "header.h"
#include "spi.h"
#include "system.h"
@@ -125,13 +126,24 @@ static int __init cpc_init(void)
err = cpc_system_drv_register();
if (err)
- bus_unregister(&cpc_bus);
+ goto unregister_bus;
+
+ err = cpc_ble_drv_register();
+ if (err)
+ goto unregister_system_driver;
err = cpc_spi_register_driver();
- if (err) {
- cpc_system_drv_unregister();
- bus_unregister(&cpc_bus);
- }
+ if (err)
+ goto unregister_ble_driver;
+
+ return 0;
+
+unregister_ble_driver:
+ cpc_ble_drv_unregister();
+unregister_system_driver:
+ cpc_system_drv_unregister();
+unregister_bus:
+ bus_unregister(&cpc_bus);
return err;
}
@@ -140,6 +152,7 @@ module_init(cpc_init);
static void __exit cpc_exit(void)
{
cpc_spi_unregister_driver();
+ cpc_ble_drv_unregister();
cpc_system_drv_unregister();
bus_unregister(&cpc_bus);
}
--
2.49.0
Powered by blists - more mailing lists