Bluetooth: hci_mrvl: Add serdev support
authorSascha Hauer <s.hauer@pengutronix.de>
Fri, 14 Jun 2019 07:23:51 +0000 (09:23 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Sat, 6 Jul 2019 10:53:56 +0000 (12:53 +0200)
This adds serdev support to the Marvell hci uart driver. Only basic
serdev support, none of the fancier features like regulator or enable
GPIO support is added for now.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Documentation/devicetree/bindings/net/marvell-bluetooth.txt [new file with mode: 0644]
drivers/bluetooth/Kconfig
drivers/bluetooth/hci_mrvl.c

diff --git a/Documentation/devicetree/bindings/net/marvell-bluetooth.txt b/Documentation/devicetree/bindings/net/marvell-bluetooth.txt
new file mode 100644 (file)
index 0000000..0e28422
--- /dev/null
@@ -0,0 +1,25 @@
+Marvell Bluetooth Chips
+-----------------------
+
+This documents the binding structure and common properties for serial
+attached Marvell Bluetooth devices. The following chips are included in
+this binding:
+
+* Marvell 88W8897 Bluetooth devices
+
+Required properties:
+ - compatible: should be:
+    "mrvl,88w8897"
+
+Optional properties:
+None so far
+
+Example:
+
+&serial0 {
+       compatible = "ns16550a";
+       ...
+       bluetooth {
+               compatible = "mrvl,88w8897";
+       };
+};
index b9c34ff9a0d310ad450f68ff83465707ffdad1e1..a3fafd781aa1c0d94ead60f411ed334fa0d7e822 100644 (file)
@@ -237,6 +237,7 @@ config BT_HCIUART_AG6XX
 config BT_HCIUART_MRVL
        bool "Marvell protocol support"
        depends on BT_HCIUART
+       depends on BT_HCIUART_SERDEV
        select BT_HCIUART_H4
        help
          Marvell is serial protocol for communication between Bluetooth
index a0a74362455ec554edeb2cf24db1f64aa5a3430a..f98e5cc343b21c22f7c054da0b315d9995cf818f 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -40,6 +42,10 @@ struct mrvl_data {
        u8 id, rev;
 };
 
+struct mrvl_serdev {
+       struct hci_uart hu;
+};
+
 struct hci_mrvl_pkt {
        __le16 lhs;
        __le16 rhs;
@@ -49,6 +55,7 @@ struct hci_mrvl_pkt {
 static int mrvl_open(struct hci_uart *hu)
 {
        struct mrvl_data *mrvl;
+       int ret;
 
        BT_DBG("hu %p", hu);
 
@@ -62,7 +69,18 @@ static int mrvl_open(struct hci_uart *hu)
        set_bit(STATE_CHIP_VER_PENDING, &mrvl->flags);
 
        hu->priv = mrvl;
+
+       if (hu->serdev) {
+               ret = serdev_device_open(hu->serdev);
+               if (ret)
+                       goto err;
+       }
+
        return 0;
+err:
+       kfree(mrvl);
+
+       return ret;
 }
 
 static int mrvl_close(struct hci_uart *hu)
@@ -71,6 +89,9 @@ static int mrvl_close(struct hci_uart *hu)
 
        BT_DBG("hu %p", hu);
 
+       if (hu->serdev)
+               serdev_device_close(hu->serdev);
+
        skb_queue_purge(&mrvl->txq);
        skb_queue_purge(&mrvl->rawq);
        kfree_skb(mrvl->rx_skb);
@@ -342,7 +363,11 @@ static int mrvl_setup(struct hci_uart *hu)
        /* Let the final ack go out before switching the baudrate */
        hci_uart_wait_until_sent(hu);
 
-       hci_uart_set_baudrate(hu, 3000000);
+       if (hu->serdev)
+               serdev_device_set_baudrate(hu->serdev, 3000000);
+       else
+               hci_uart_set_baudrate(hu, 3000000);
+
        hci_uart_set_flow_control(hu, false);
 
        err = mrvl_load_firmware(hu->hdev, "mrvl/uart8897_bt.bin");
@@ -365,12 +390,54 @@ static const struct hci_uart_proto mrvl_proto = {
        .dequeue        = mrvl_dequeue,
 };
 
+static int mrvl_serdev_probe(struct serdev_device *serdev)
+{
+       struct mrvl_serdev *mrvldev;
+
+       mrvldev = devm_kzalloc(&serdev->dev, sizeof(*mrvldev), GFP_KERNEL);
+       if (!mrvldev)
+               return -ENOMEM;
+
+       mrvldev->hu.serdev = serdev;
+       serdev_device_set_drvdata(serdev, mrvldev);
+
+       return hci_uart_register_device(&mrvldev->hu, &mrvl_proto);
+}
+
+static void mrvl_serdev_remove(struct serdev_device *serdev)
+{
+       struct mrvl_serdev *mrvldev = serdev_device_get_drvdata(serdev);
+
+       hci_uart_unregister_device(&mrvldev->hu);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mrvl_bluetooth_of_match[] = {
+       { .compatible = "mrvl,88w8897" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, mrvl_bluetooth_of_match);
+#endif
+
+static struct serdev_device_driver mrvl_serdev_driver = {
+       .probe = mrvl_serdev_probe,
+       .remove = mrvl_serdev_remove,
+       .driver = {
+               .name = "hci_uart_mrvl",
+               .of_match_table = of_match_ptr(mrvl_bluetooth_of_match),
+       },
+};
+
 int __init mrvl_init(void)
 {
+       serdev_device_driver_register(&mrvl_serdev_driver);
+
        return hci_uart_register_proto(&mrvl_proto);
 }
 
 int __exit mrvl_deinit(void)
 {
+       serdev_device_driver_unregister(&mrvl_serdev_driver);
+
        return hci_uart_unregister_proto(&mrvl_proto);
 }