18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Bluetooth HCI serdev driver lib
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2017  Linaro, Ltd., Rob Herring <robh@kernel.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Based on hci_ldisc.c:
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  Copyright (C) 2000-2001  Qualcomm Incorporated
108c2ecf20Sopenharmony_ci *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
118c2ecf20Sopenharmony_ci *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci#include <linux/serdev.h>
178c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
208c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "hci_uart.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct hci_dev *hdev = hu->hdev;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	/* Update HCI stat counters */
298c2ecf20Sopenharmony_ci	switch (pkt_type) {
308c2ecf20Sopenharmony_ci	case HCI_COMMAND_PKT:
318c2ecf20Sopenharmony_ci		hdev->stat.cmd_tx++;
328c2ecf20Sopenharmony_ci		break;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	case HCI_ACLDATA_PKT:
358c2ecf20Sopenharmony_ci		hdev->stat.acl_tx++;
368c2ecf20Sopenharmony_ci		break;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	case HCI_SCODATA_PKT:
398c2ecf20Sopenharmony_ci		hdev->stat.sco_tx++;
408c2ecf20Sopenharmony_ci		break;
418c2ecf20Sopenharmony_ci	}
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct sk_buff *skb = hu->tx_skb;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (!skb) {
498c2ecf20Sopenharmony_ci		if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
508c2ecf20Sopenharmony_ci			skb = hu->proto->dequeue(hu);
518c2ecf20Sopenharmony_ci	} else
528c2ecf20Sopenharmony_ci		hu->tx_skb = NULL;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return skb;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void hci_uart_write_work(struct work_struct *work)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
608c2ecf20Sopenharmony_ci	struct serdev_device *serdev = hu->serdev;
618c2ecf20Sopenharmony_ci	struct hci_dev *hdev = hu->hdev;
628c2ecf20Sopenharmony_ci	struct sk_buff *skb;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	/* REVISIT:
658c2ecf20Sopenharmony_ci	 * should we cope with bad skbs or ->write() returning an error value?
668c2ecf20Sopenharmony_ci	 */
678c2ecf20Sopenharmony_ci	do {
688c2ecf20Sopenharmony_ci		clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		while ((skb = hci_uart_dequeue(hu))) {
718c2ecf20Sopenharmony_ci			int len;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci			len = serdev_device_write_buf(serdev,
748c2ecf20Sopenharmony_ci						      skb->data, skb->len);
758c2ecf20Sopenharmony_ci			hdev->stat.byte_tx += len;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci			skb_pull(skb, len);
788c2ecf20Sopenharmony_ci			if (skb->len) {
798c2ecf20Sopenharmony_ci				hu->tx_skb = skb;
808c2ecf20Sopenharmony_ci				break;
818c2ecf20Sopenharmony_ci			}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci			hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
848c2ecf20Sopenharmony_ci			kfree_skb(skb);
858c2ecf20Sopenharmony_ci		}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		clear_bit(HCI_UART_SENDING, &hu->tx_state);
888c2ecf20Sopenharmony_ci	} while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* ------- Interface to HCI layer ------ */
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/* Reset device */
948c2ecf20Sopenharmony_cistatic int hci_uart_flush(struct hci_dev *hdev)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct hci_uart *hu  = hci_get_drvdata(hdev);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	BT_DBG("hdev %p serdev %p", hdev, hu->serdev);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (hu->tx_skb) {
1018c2ecf20Sopenharmony_ci		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* Flush any pending characters in the driver and discipline. */
1058c2ecf20Sopenharmony_ci	serdev_device_write_flush(hu->serdev);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
1088c2ecf20Sopenharmony_ci		hu->proto->flush(hu);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* Initialize device */
1148c2ecf20Sopenharmony_cistatic int hci_uart_open(struct hci_dev *hdev)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct hci_uart *hu = hci_get_drvdata(hdev);
1178c2ecf20Sopenharmony_ci	int err;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	BT_DBG("%s %p", hdev->name, hdev);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by
1228c2ecf20Sopenharmony_ci	 * driver, BT SoC is completely turned OFF during
1238c2ecf20Sopenharmony_ci	 * BT OFF. Upon next BT ON UART port should be opened.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
1268c2ecf20Sopenharmony_ci		err = serdev_device_open(hu->serdev);
1278c2ecf20Sopenharmony_ci		if (err)
1288c2ecf20Sopenharmony_ci			return err;
1298c2ecf20Sopenharmony_ci		set_bit(HCI_UART_PROTO_READY, &hu->flags);
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Undo clearing this from hci_uart_close() */
1338c2ecf20Sopenharmony_ci	hdev->flush = hci_uart_flush;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* Close device */
1398c2ecf20Sopenharmony_cistatic int hci_uart_close(struct hci_dev *hdev)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct hci_uart *hu = hci_get_drvdata(hdev);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	BT_DBG("hdev %p", hdev);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
1468c2ecf20Sopenharmony_ci		return 0;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	hci_uart_flush(hdev);
1498c2ecf20Sopenharmony_ci	hdev->flush = NULL;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver,
1528c2ecf20Sopenharmony_ci	 * BT SOC is completely powered OFF during BT OFF, holding port
1538c2ecf20Sopenharmony_ci	 * open may drain the battery.
1548c2ecf20Sopenharmony_ci	 */
1558c2ecf20Sopenharmony_ci	if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) {
1568c2ecf20Sopenharmony_ci		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
1578c2ecf20Sopenharmony_ci		serdev_device_close(hu->serdev);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/* Send frames from HCI layer */
1648c2ecf20Sopenharmony_cistatic int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct hci_uart *hu = hci_get_drvdata(hdev);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
1698c2ecf20Sopenharmony_ci	       skb->len);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	hu->proto->enqueue(hu, skb);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	hci_uart_tx_wakeup(hu);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int hci_uart_setup(struct hci_dev *hdev)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct hci_uart *hu = hci_get_drvdata(hdev);
1818c2ecf20Sopenharmony_ci	struct hci_rp_read_local_version *ver;
1828c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1838c2ecf20Sopenharmony_ci	unsigned int speed;
1848c2ecf20Sopenharmony_ci	int err;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Init speed if any */
1878c2ecf20Sopenharmony_ci	if (hu->init_speed)
1888c2ecf20Sopenharmony_ci		speed = hu->init_speed;
1898c2ecf20Sopenharmony_ci	else if (hu->proto->init_speed)
1908c2ecf20Sopenharmony_ci		speed = hu->proto->init_speed;
1918c2ecf20Sopenharmony_ci	else
1928c2ecf20Sopenharmony_ci		speed = 0;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (speed)
1958c2ecf20Sopenharmony_ci		serdev_device_set_baudrate(hu->serdev, speed);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/* Operational speed if any */
1988c2ecf20Sopenharmony_ci	if (hu->oper_speed)
1998c2ecf20Sopenharmony_ci		speed = hu->oper_speed;
2008c2ecf20Sopenharmony_ci	else if (hu->proto->oper_speed)
2018c2ecf20Sopenharmony_ci		speed = hu->proto->oper_speed;
2028c2ecf20Sopenharmony_ci	else
2038c2ecf20Sopenharmony_ci		speed = 0;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (hu->proto->set_baudrate && speed) {
2068c2ecf20Sopenharmony_ci		err = hu->proto->set_baudrate(hu, speed);
2078c2ecf20Sopenharmony_ci		if (err)
2088c2ecf20Sopenharmony_ci			bt_dev_err(hdev, "Failed to set baudrate");
2098c2ecf20Sopenharmony_ci		else
2108c2ecf20Sopenharmony_ci			serdev_device_set_baudrate(hu->serdev, speed);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (hu->proto->setup)
2148c2ecf20Sopenharmony_ci		return hu->proto->setup(hu);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags))
2178c2ecf20Sopenharmony_ci		return 0;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
2208c2ecf20Sopenharmony_ci			     HCI_INIT_TIMEOUT);
2218c2ecf20Sopenharmony_ci	if (IS_ERR(skb)) {
2228c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "Reading local version info failed (%ld)",
2238c2ecf20Sopenharmony_ci			   PTR_ERR(skb));
2248c2ecf20Sopenharmony_ci		return 0;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (skb->len != sizeof(*ver))
2288c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "Event length mismatch for version info");
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	kfree_skb(skb);
2318c2ecf20Sopenharmony_ci	return 0;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci/** hci_uart_write_wakeup - transmit buffer wakeup
2358c2ecf20Sopenharmony_ci * @serdev: serial device
2368c2ecf20Sopenharmony_ci *
2378c2ecf20Sopenharmony_ci * This function is called by the serdev framework when it accepts
2388c2ecf20Sopenharmony_ci * more data being sent.
2398c2ecf20Sopenharmony_ci */
2408c2ecf20Sopenharmony_cistatic void hci_uart_write_wakeup(struct serdev_device *serdev)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct hci_uart *hu = serdev_device_get_drvdata(serdev);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	BT_DBG("");
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (!hu || serdev != hu->serdev) {
2478c2ecf20Sopenharmony_ci		WARN_ON(1);
2488c2ecf20Sopenharmony_ci		return;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
2528c2ecf20Sopenharmony_ci		hci_uart_tx_wakeup(hu);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/** hci_uart_receive_buf - receive buffer wakeup
2568c2ecf20Sopenharmony_ci * @serdev: serial device
2578c2ecf20Sopenharmony_ci * @data:   pointer to received data
2588c2ecf20Sopenharmony_ci * @count:  count of received data in bytes
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * This function is called by the serdev framework when it received data
2618c2ecf20Sopenharmony_ci * in the RX buffer.
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci * Return: number of processed bytes
2648c2ecf20Sopenharmony_ci */
2658c2ecf20Sopenharmony_cistatic int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data,
2668c2ecf20Sopenharmony_ci				   size_t count)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct hci_uart *hu = serdev_device_get_drvdata(serdev);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (!hu || serdev != hu->serdev) {
2718c2ecf20Sopenharmony_ci		WARN_ON(1);
2728c2ecf20Sopenharmony_ci		return 0;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
2768c2ecf20Sopenharmony_ci		return 0;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* It does not need a lock here as it is already protected by a mutex in
2798c2ecf20Sopenharmony_ci	 * tty caller
2808c2ecf20Sopenharmony_ci	 */
2818c2ecf20Sopenharmony_ci	hu->proto->recv(hu, data, count);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (hu->hdev)
2848c2ecf20Sopenharmony_ci		hu->hdev->stat.byte_rx += count;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return count;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic const struct serdev_device_ops hci_serdev_client_ops = {
2908c2ecf20Sopenharmony_ci	.receive_buf = hci_uart_receive_buf,
2918c2ecf20Sopenharmony_ci	.write_wakeup = hci_uart_write_wakeup,
2928c2ecf20Sopenharmony_ci};
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ciint hci_uart_register_device(struct hci_uart *hu,
2958c2ecf20Sopenharmony_ci			     const struct hci_uart_proto *p)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	int err;
2988c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	BT_DBG("");
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (percpu_init_rwsem(&hu->proto_lock))
3058c2ecf20Sopenharmony_ci		return -ENOMEM;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	err = serdev_device_open(hu->serdev);
3088c2ecf20Sopenharmony_ci	if (err)
3098c2ecf20Sopenharmony_ci		goto err_rwsem;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	err = p->open(hu);
3128c2ecf20Sopenharmony_ci	if (err)
3138c2ecf20Sopenharmony_ci		goto err_open;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	hu->proto = p;
3168c2ecf20Sopenharmony_ci	set_bit(HCI_UART_PROTO_READY, &hu->flags);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* Initialize and register HCI device */
3198c2ecf20Sopenharmony_ci	hdev = hci_alloc_dev();
3208c2ecf20Sopenharmony_ci	if (!hdev) {
3218c2ecf20Sopenharmony_ci		BT_ERR("Can't allocate HCI device");
3228c2ecf20Sopenharmony_ci		err = -ENOMEM;
3238c2ecf20Sopenharmony_ci		goto err_alloc;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	hu->hdev = hdev;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	hdev->bus = HCI_UART;
3298c2ecf20Sopenharmony_ci	hci_set_drvdata(hdev, hu);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	INIT_WORK(&hu->init_ready, hci_uart_init_work);
3328c2ecf20Sopenharmony_ci	INIT_WORK(&hu->write_work, hci_uart_write_work);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Only when vendor specific setup callback is provided, consider
3358c2ecf20Sopenharmony_ci	 * the manufacturer information valid. This avoids filling in the
3368c2ecf20Sopenharmony_ci	 * value for Ericsson when nothing is specified.
3378c2ecf20Sopenharmony_ci	 */
3388c2ecf20Sopenharmony_ci	if (hu->proto->setup)
3398c2ecf20Sopenharmony_ci		hdev->manufacturer = hu->proto->manufacturer;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	hdev->open  = hci_uart_open;
3428c2ecf20Sopenharmony_ci	hdev->close = hci_uart_close;
3438c2ecf20Sopenharmony_ci	hdev->flush = hci_uart_flush;
3448c2ecf20Sopenharmony_ci	hdev->send  = hci_uart_send_frame;
3458c2ecf20Sopenharmony_ci	hdev->setup = hci_uart_setup;
3468c2ecf20Sopenharmony_ci	SET_HCIDEV_DEV(hdev, &hu->serdev->dev);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
3498c2ecf20Sopenharmony_ci		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
3528c2ecf20Sopenharmony_ci		set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
3558c2ecf20Sopenharmony_ci		hdev->dev_type = HCI_AMP;
3568c2ecf20Sopenharmony_ci	else
3578c2ecf20Sopenharmony_ci		hdev->dev_type = HCI_PRIMARY;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
3608c2ecf20Sopenharmony_ci		return 0;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (hci_register_dev(hdev) < 0) {
3638c2ecf20Sopenharmony_ci		BT_ERR("Can't register HCI device");
3648c2ecf20Sopenharmony_ci		err = -ENODEV;
3658c2ecf20Sopenharmony_ci		goto err_register;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	set_bit(HCI_UART_REGISTERED, &hu->flags);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cierr_register:
3738c2ecf20Sopenharmony_ci	hci_free_dev(hdev);
3748c2ecf20Sopenharmony_cierr_alloc:
3758c2ecf20Sopenharmony_ci	clear_bit(HCI_UART_PROTO_READY, &hu->flags);
3768c2ecf20Sopenharmony_ci	p->close(hu);
3778c2ecf20Sopenharmony_cierr_open:
3788c2ecf20Sopenharmony_ci	serdev_device_close(hu->serdev);
3798c2ecf20Sopenharmony_cierr_rwsem:
3808c2ecf20Sopenharmony_ci	percpu_free_rwsem(&hu->proto_lock);
3818c2ecf20Sopenharmony_ci	return err;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hci_uart_register_device);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_civoid hci_uart_unregister_device(struct hci_uart *hu)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	struct hci_dev *hdev = hu->hdev;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	cancel_work_sync(&hu->init_ready);
3908c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_REGISTERED, &hu->flags))
3918c2ecf20Sopenharmony_ci		hci_unregister_dev(hdev);
3928c2ecf20Sopenharmony_ci	hci_free_dev(hdev);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	cancel_work_sync(&hu->write_work);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	hu->proto->close(hu);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
3998c2ecf20Sopenharmony_ci		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
4008c2ecf20Sopenharmony_ci		serdev_device_close(hu->serdev);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci	percpu_free_rwsem(&hu->proto_lock);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hci_uart_unregister_device);
405