Skip to content

Commit 05ba533

Browse files
Thierry Escandeholtmann
authored andcommitted
Bluetooth: hci_qca: Add serdev support
Add support for Qualcomm serial slave devices. Probe the serial device, retrieve its maximum speed and register a new hci uart device. Signed-off-by: Thierry Escande <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 52b0900 commit 05ba533

File tree

2 files changed

+109
-2
lines changed

2 files changed

+109
-2
lines changed

drivers/bluetooth/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ config BT_HCIUART_BCM
197197
config BT_HCIUART_QCA
198198
bool "Qualcomm Atheros protocol support"
199199
depends on BT_HCIUART
200+
depends on BT_HCIUART_SERDEV
200201
select BT_HCIUART_H4
201202
select BT_QCA
202203
help

drivers/bluetooth/hci_qca.c

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@
2929
*/
3030

3131
#include <linux/kernel.h>
32+
#include <linux/clk.h>
3233
#include <linux/debugfs.h>
34+
#include <linux/gpio/consumer.h>
35+
#include <linux/mod_devicetable.h>
36+
#include <linux/module.h>
37+
#include <linux/serdev.h>
3338

3439
#include <net/bluetooth/bluetooth.h>
3540
#include <net/bluetooth/hci_core.h>
@@ -50,6 +55,9 @@
5055
#define IBS_TX_IDLE_TIMEOUT_MS 2000
5156
#define BAUDRATE_SETTLE_TIMEOUT_MS 300
5257

58+
/* susclk rate */
59+
#define SUSCLK_RATE_32KHZ 32768
60+
5361
/* HCI_IBS transmit side sleep protocol states */
5462
enum tx_ibs_states {
5563
HCI_IBS_TX_ASLEEP,
@@ -111,6 +119,12 @@ struct qca_data {
111119
u64 votes_off;
112120
};
113121

122+
struct qca_serdev {
123+
struct hci_uart serdev_hu;
124+
struct gpio_desc *bt_en;
125+
struct clk *susclk;
126+
};
127+
114128
static void __serial_clock_on(struct tty_struct *tty)
115129
{
116130
/* TODO: Some chipset requires to enable UART clock on client
@@ -386,6 +400,7 @@ static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
386400
/* Initialize protocol */
387401
static int qca_open(struct hci_uart *hu)
388402
{
403+
struct qca_serdev *qcadev;
389404
struct qca_data *qca;
390405

391406
BT_DBG("hu %p qca_open", hu);
@@ -444,6 +459,13 @@ static int qca_open(struct hci_uart *hu)
444459
timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
445460
qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
446461

462+
if (hu->serdev) {
463+
serdev_device_open(hu->serdev);
464+
465+
qcadev = serdev_device_get_drvdata(hu->serdev);
466+
gpiod_set_value_cansleep(qcadev->bt_en, 1);
467+
}
468+
447469
BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
448470
qca->tx_idle_delay, qca->wake_retrans);
449471

@@ -512,6 +534,7 @@ static int qca_flush(struct hci_uart *hu)
512534
/* Close protocol */
513535
static int qca_close(struct hci_uart *hu)
514536
{
537+
struct qca_serdev *qcadev;
515538
struct qca_data *qca = hu->priv;
516539

517540
BT_DBG("hu %p qca close", hu);
@@ -525,6 +548,13 @@ static int qca_close(struct hci_uart *hu)
525548
destroy_workqueue(qca->workqueue);
526549
qca->hu = NULL;
527550

551+
if (hu->serdev) {
552+
serdev_device_close(hu->serdev);
553+
554+
qcadev = serdev_device_get_drvdata(hu->serdev);
555+
gpiod_set_value_cansleep(qcadev->bt_en, 0);
556+
}
557+
528558
kfree_skb(qca->rx_skb);
529559

530560
hu->priv = NULL;
@@ -885,6 +915,14 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
885915
return 0;
886916
}
887917

918+
static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
919+
{
920+
if (hu->serdev)
921+
serdev_device_set_baudrate(hu->serdev, speed);
922+
else
923+
hci_uart_set_baudrate(hu, speed);
924+
}
925+
888926
static int qca_setup(struct hci_uart *hu)
889927
{
890928
struct hci_dev *hdev = hu->hdev;
@@ -905,7 +943,7 @@ static int qca_setup(struct hci_uart *hu)
905943
speed = hu->proto->init_speed;
906944

907945
if (speed)
908-
hci_uart_set_baudrate(hu, speed);
946+
host_set_baudrate(hu, speed);
909947

910948
/* Setup user speed if needed */
911949
speed = 0;
@@ -924,7 +962,7 @@ static int qca_setup(struct hci_uart *hu)
924962
ret);
925963
return ret;
926964
}
927-
hci_uart_set_baudrate(hu, speed);
965+
host_set_baudrate(hu, speed);
928966
}
929967

930968
/* Setup patch / NVM configurations */
@@ -964,12 +1002,80 @@ static struct hci_uart_proto qca_proto = {
9641002
.dequeue = qca_dequeue,
9651003
};
9661004

1005+
static int qca_serdev_probe(struct serdev_device *serdev)
1006+
{
1007+
struct qca_serdev *qcadev;
1008+
int err;
1009+
1010+
qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
1011+
if (!qcadev)
1012+
return -ENOMEM;
1013+
1014+
qcadev->serdev_hu.serdev = serdev;
1015+
serdev_device_set_drvdata(serdev, qcadev);
1016+
1017+
qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable",
1018+
GPIOD_OUT_LOW);
1019+
if (IS_ERR(qcadev->bt_en)) {
1020+
dev_err(&serdev->dev, "failed to acquire enable gpio\n");
1021+
return PTR_ERR(qcadev->bt_en);
1022+
}
1023+
1024+
qcadev->susclk = devm_clk_get(&serdev->dev, NULL);
1025+
if (IS_ERR(qcadev->susclk)) {
1026+
dev_err(&serdev->dev, "failed to acquire clk\n");
1027+
return PTR_ERR(qcadev->susclk);
1028+
}
1029+
1030+
err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
1031+
if (err)
1032+
return err;
1033+
1034+
err = clk_prepare_enable(qcadev->susclk);
1035+
if (err)
1036+
return err;
1037+
1038+
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
1039+
if (err)
1040+
clk_disable_unprepare(qcadev->susclk);
1041+
1042+
return err;
1043+
}
1044+
1045+
static void qca_serdev_remove(struct serdev_device *serdev)
1046+
{
1047+
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
1048+
1049+
hci_uart_unregister_device(&qcadev->serdev_hu);
1050+
1051+
clk_disable_unprepare(qcadev->susclk);
1052+
}
1053+
1054+
static const struct of_device_id qca_bluetooth_of_match[] = {
1055+
{ .compatible = "qcom,qca6174-bt" },
1056+
{ /* sentinel */ }
1057+
};
1058+
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
1059+
1060+
static struct serdev_device_driver qca_serdev_driver = {
1061+
.probe = qca_serdev_probe,
1062+
.remove = qca_serdev_remove,
1063+
.driver = {
1064+
.name = "hci_uart_qca",
1065+
.of_match_table = qca_bluetooth_of_match,
1066+
},
1067+
};
1068+
9671069
int __init qca_init(void)
9681070
{
1071+
serdev_device_driver_register(&qca_serdev_driver);
1072+
9691073
return hci_uart_register_proto(&qca_proto);
9701074
}
9711075

9721076
int __exit qca_deinit(void)
9731077
{
1078+
serdev_device_driver_unregister(&qca_serdev_driver);
1079+
9741080
return hci_uart_unregister_proto(&qca_proto);
9751081
}

0 commit comments

Comments
 (0)