1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2016, Linaro Ltd.
4 * Copyright (c) 2015, Sony Mobile Communications Inc.
7 #include <linux/module.h>
8 #include <linux/slab.h>
9 #include <linux/rpmsg.h>
12 #include <linux/soc/qcom/wcnss_ctrl.h>
13 #include <linux/platform_device.h>
15 #include <net/bluetooth/bluetooth.h>
16 #include <net/bluetooth/hci_core.h>
23 struct rpmsg_endpoint
*acl_channel
;
24 struct rpmsg_endpoint
*cmd_channel
;
27 static int btqcomsmd_recv(struct hci_dev
*hdev
, unsigned int type
,
28 const void *data
, size_t count
)
32 /* Use GFP_ATOMIC as we're in IRQ context */
33 skb
= bt_skb_alloc(count
, GFP_ATOMIC
);
39 hci_skb_pkt_type(skb
) = type
;
40 skb_put_data(skb
, data
, count
);
42 return hci_recv_frame(hdev
, skb
);
45 static int btqcomsmd_acl_callback(struct rpmsg_device
*rpdev
, void *data
,
46 int count
, void *priv
, u32 addr
)
48 struct btqcomsmd
*btq
= priv
;
50 btq
->hdev
->stat
.byte_rx
+= count
;
51 return btqcomsmd_recv(btq
->hdev
, HCI_ACLDATA_PKT
, data
, count
);
54 static int btqcomsmd_cmd_callback(struct rpmsg_device
*rpdev
, void *data
,
55 int count
, void *priv
, u32 addr
)
57 struct btqcomsmd
*btq
= priv
;
59 btq
->hdev
->stat
.byte_rx
+= count
;
60 return btqcomsmd_recv(btq
->hdev
, HCI_EVENT_PKT
, data
, count
);
63 static int btqcomsmd_send(struct hci_dev
*hdev
, struct sk_buff
*skb
)
65 struct btqcomsmd
*btq
= hci_get_drvdata(hdev
);
68 switch (hci_skb_pkt_type(skb
)) {
70 ret
= rpmsg_send(btq
->acl_channel
, skb
->data
, skb
->len
);
76 hdev
->stat
.byte_tx
+= skb
->len
;
79 ret
= rpmsg_send(btq
->cmd_channel
, skb
->data
, skb
->len
);
85 hdev
->stat
.byte_tx
+= skb
->len
;
98 static int btqcomsmd_open(struct hci_dev
*hdev
)
103 static int btqcomsmd_close(struct hci_dev
*hdev
)
108 static int btqcomsmd_setup(struct hci_dev
*hdev
)
112 skb
= __hci_cmd_sync(hdev
, HCI_OP_RESET
, 0, NULL
, HCI_INIT_TIMEOUT
);
117 /* Devices do not have persistent storage for BD address. Retrieve
118 * it from the firmware node property.
120 set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY
, &hdev
->quirks
);
125 static int btqcomsmd_probe(struct platform_device
*pdev
)
127 struct btqcomsmd
*btq
;
128 struct hci_dev
*hdev
;
132 btq
= devm_kzalloc(&pdev
->dev
, sizeof(*btq
), GFP_KERNEL
);
136 wcnss
= dev_get_drvdata(pdev
->dev
.parent
);
138 btq
->acl_channel
= qcom_wcnss_open_channel(wcnss
, "APPS_RIVA_BT_ACL",
139 btqcomsmd_acl_callback
, btq
);
140 if (IS_ERR(btq
->acl_channel
))
141 return PTR_ERR(btq
->acl_channel
);
143 btq
->cmd_channel
= qcom_wcnss_open_channel(wcnss
, "APPS_RIVA_BT_CMD",
144 btqcomsmd_cmd_callback
, btq
);
145 if (IS_ERR(btq
->cmd_channel
))
146 return PTR_ERR(btq
->cmd_channel
);
148 hdev
= hci_alloc_dev();
152 hci_set_drvdata(hdev
, btq
);
154 SET_HCIDEV_DEV(hdev
, &pdev
->dev
);
157 hdev
->open
= btqcomsmd_open
;
158 hdev
->close
= btqcomsmd_close
;
159 hdev
->send
= btqcomsmd_send
;
160 hdev
->setup
= btqcomsmd_setup
;
161 hdev
->set_bdaddr
= qca_set_bdaddr_rome
;
163 ret
= hci_register_dev(hdev
);
169 platform_set_drvdata(pdev
, btq
);
174 static int btqcomsmd_remove(struct platform_device
*pdev
)
176 struct btqcomsmd
*btq
= platform_get_drvdata(pdev
);
178 hci_unregister_dev(btq
->hdev
);
179 hci_free_dev(btq
->hdev
);
181 rpmsg_destroy_ept(btq
->cmd_channel
);
182 rpmsg_destroy_ept(btq
->acl_channel
);
187 static const struct of_device_id btqcomsmd_of_match
[] = {
188 { .compatible
= "qcom,wcnss-bt", },
191 MODULE_DEVICE_TABLE(of
, btqcomsmd_of_match
);
193 static struct platform_driver btqcomsmd_driver
= {
194 .probe
= btqcomsmd_probe
,
195 .remove
= btqcomsmd_remove
,
198 .of_match_table
= btqcomsmd_of_match
,
202 module_platform_driver(btqcomsmd_driver
);
204 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
205 MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
206 MODULE_LICENSE("GPL v2");