Commit be70e5e7 authored by Sascha Hauer's avatar Sascha Hauer Committed by Marcel Holtmann
Browse files

Bluetooth: hci_mrvl: Add serdev support



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: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent a55b8964
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
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";
	};
};
+1 −0
Original line number Diff line number Diff line
@@ -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
+68 −1
Original line number Diff line number Diff line
@@ -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);

	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);
}