.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * |
---|
3 | 4 | * Bluetooth HCI UART driver for marvell devices |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2016 Marvell International Ltd. |
---|
6 | 7 | * Copyright (C) 2016 Intel Corporation |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License |
---|
19 | | - * along with this program; if not, write to the Free Software |
---|
20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
21 | | - * |
---|
22 | 8 | */ |
---|
23 | 9 | |
---|
24 | 10 | #include <linux/kernel.h> |
---|
.. | .. |
---|
27 | 13 | #include <linux/firmware.h> |
---|
28 | 14 | #include <linux/module.h> |
---|
29 | 15 | #include <linux/tty.h> |
---|
| 16 | +#include <linux/of.h> |
---|
| 17 | +#include <linux/serdev.h> |
---|
30 | 18 | |
---|
31 | 19 | #include <net/bluetooth/bluetooth.h> |
---|
32 | 20 | #include <net/bluetooth/hci_core.h> |
---|
.. | .. |
---|
54 | 42 | u8 id, rev; |
---|
55 | 43 | }; |
---|
56 | 44 | |
---|
| 45 | +struct mrvl_serdev { |
---|
| 46 | + struct hci_uart hu; |
---|
| 47 | +}; |
---|
| 48 | + |
---|
57 | 49 | struct hci_mrvl_pkt { |
---|
58 | 50 | __le16 lhs; |
---|
59 | 51 | __le16 rhs; |
---|
.. | .. |
---|
63 | 55 | static int mrvl_open(struct hci_uart *hu) |
---|
64 | 56 | { |
---|
65 | 57 | struct mrvl_data *mrvl; |
---|
| 58 | + int ret; |
---|
66 | 59 | |
---|
67 | 60 | BT_DBG("hu %p", hu); |
---|
68 | 61 | |
---|
.. | .. |
---|
79 | 72 | set_bit(STATE_CHIP_VER_PENDING, &mrvl->flags); |
---|
80 | 73 | |
---|
81 | 74 | hu->priv = mrvl; |
---|
| 75 | + |
---|
| 76 | + if (hu->serdev) { |
---|
| 77 | + ret = serdev_device_open(hu->serdev); |
---|
| 78 | + if (ret) |
---|
| 79 | + goto err; |
---|
| 80 | + } |
---|
| 81 | + |
---|
82 | 82 | return 0; |
---|
| 83 | +err: |
---|
| 84 | + kfree(mrvl); |
---|
| 85 | + |
---|
| 86 | + return ret; |
---|
83 | 87 | } |
---|
84 | 88 | |
---|
85 | 89 | static int mrvl_close(struct hci_uart *hu) |
---|
.. | .. |
---|
87 | 91 | struct mrvl_data *mrvl = hu->priv; |
---|
88 | 92 | |
---|
89 | 93 | BT_DBG("hu %p", hu); |
---|
| 94 | + |
---|
| 95 | + if (hu->serdev) |
---|
| 96 | + serdev_device_close(hu->serdev); |
---|
90 | 97 | |
---|
91 | 98 | skb_queue_purge(&mrvl->txq); |
---|
92 | 99 | skb_queue_purge(&mrvl->rawq); |
---|
.. | .. |
---|
356 | 363 | return -EINVAL; |
---|
357 | 364 | } |
---|
358 | 365 | |
---|
359 | | - hci_uart_set_baudrate(hu, 3000000); |
---|
| 366 | + /* Let the final ack go out before switching the baudrate */ |
---|
| 367 | + hci_uart_wait_until_sent(hu); |
---|
| 368 | + |
---|
| 369 | + if (hu->serdev) |
---|
| 370 | + serdev_device_set_baudrate(hu->serdev, 3000000); |
---|
| 371 | + else |
---|
| 372 | + hci_uart_set_baudrate(hu, 3000000); |
---|
| 373 | + |
---|
360 | 374 | hci_uart_set_flow_control(hu, false); |
---|
361 | 375 | |
---|
362 | 376 | err = mrvl_load_firmware(hu->hdev, "mrvl/uart8897_bt.bin"); |
---|
.. | .. |
---|
379 | 393 | .dequeue = mrvl_dequeue, |
---|
380 | 394 | }; |
---|
381 | 395 | |
---|
| 396 | +static int mrvl_serdev_probe(struct serdev_device *serdev) |
---|
| 397 | +{ |
---|
| 398 | + struct mrvl_serdev *mrvldev; |
---|
| 399 | + |
---|
| 400 | + mrvldev = devm_kzalloc(&serdev->dev, sizeof(*mrvldev), GFP_KERNEL); |
---|
| 401 | + if (!mrvldev) |
---|
| 402 | + return -ENOMEM; |
---|
| 403 | + |
---|
| 404 | + mrvldev->hu.serdev = serdev; |
---|
| 405 | + serdev_device_set_drvdata(serdev, mrvldev); |
---|
| 406 | + |
---|
| 407 | + return hci_uart_register_device(&mrvldev->hu, &mrvl_proto); |
---|
| 408 | +} |
---|
| 409 | + |
---|
| 410 | +static void mrvl_serdev_remove(struct serdev_device *serdev) |
---|
| 411 | +{ |
---|
| 412 | + struct mrvl_serdev *mrvldev = serdev_device_get_drvdata(serdev); |
---|
| 413 | + |
---|
| 414 | + hci_uart_unregister_device(&mrvldev->hu); |
---|
| 415 | +} |
---|
| 416 | + |
---|
| 417 | +#ifdef CONFIG_OF |
---|
| 418 | +static const struct of_device_id mrvl_bluetooth_of_match[] = { |
---|
| 419 | + { .compatible = "mrvl,88w8897" }, |
---|
| 420 | + { }, |
---|
| 421 | +}; |
---|
| 422 | +MODULE_DEVICE_TABLE(of, mrvl_bluetooth_of_match); |
---|
| 423 | +#endif |
---|
| 424 | + |
---|
| 425 | +static struct serdev_device_driver mrvl_serdev_driver = { |
---|
| 426 | + .probe = mrvl_serdev_probe, |
---|
| 427 | + .remove = mrvl_serdev_remove, |
---|
| 428 | + .driver = { |
---|
| 429 | + .name = "hci_uart_mrvl", |
---|
| 430 | + .of_match_table = of_match_ptr(mrvl_bluetooth_of_match), |
---|
| 431 | + }, |
---|
| 432 | +}; |
---|
| 433 | + |
---|
382 | 434 | int __init mrvl_init(void) |
---|
383 | 435 | { |
---|
| 436 | + serdev_device_driver_register(&mrvl_serdev_driver); |
---|
| 437 | + |
---|
384 | 438 | return hci_uart_register_proto(&mrvl_proto); |
---|
385 | 439 | } |
---|
386 | 440 | |
---|
387 | 441 | int __exit mrvl_deinit(void) |
---|
388 | 442 | { |
---|
| 443 | + serdev_device_driver_unregister(&mrvl_serdev_driver); |
---|
| 444 | + |
---|
389 | 445 | return hci_uart_unregister_proto(&mrvl_proto); |
---|
390 | 446 | } |
---|