2 * Copyright (c) 2016, Linaro Ltd.
3 * Copyright (c) 2015, Sony Mobile Communications Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <linux/rpmsg.h>
20 #include <linux/soc/qcom/wcnss_ctrl.h>
21 #include <linux/platform_device.h>
23 #include <net/bluetooth/bluetooth.h>
24 #include <net/bluetooth/hci_core.h>
32 struct rpmsg_endpoint
*acl_channel
;
33 struct rpmsg_endpoint
*cmd_channel
;
36 static int btqcomsmd_recv(struct hci_dev
*hdev
, unsigned int type
,
37 const void *data
, size_t count
)
41 /* Use GFP_ATOMIC as we're in IRQ context */
42 skb
= bt_skb_alloc(count
, GFP_ATOMIC
);
48 hci_skb_pkt_type(skb
) = type
;
49 skb_put_data(skb
, data
, count
);
51 return hci_recv_frame(hdev
, skb
);
54 static int btqcomsmd_acl_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_ACLDATA_PKT
, data
, count
);
63 static int btqcomsmd_cmd_callback(struct rpmsg_device
*rpdev
, void *data
,
64 int count
, void *priv
, u32 addr
)
66 struct btqcomsmd
*btq
= priv
;
68 btq
->hdev
->stat
.byte_rx
+= count
;
69 return btqcomsmd_recv(btq
->hdev
, HCI_EVENT_PKT
, data
, count
);
72 static int btqcomsmd_send(struct hci_dev
*hdev
, struct sk_buff
*skb
)
74 struct btqcomsmd
*btq
= hci_get_drvdata(hdev
);
77 switch (hci_skb_pkt_type(skb
)) {
79 ret
= rpmsg_send(btq
->acl_channel
, skb
->data
, skb
->len
);
85 hdev
->stat
.byte_tx
+= skb
->len
;
88 ret
= rpmsg_send(btq
->cmd_channel
, skb
->data
, skb
->len
);
94 hdev
->stat
.byte_tx
+= skb
->len
;
107 static int btqcomsmd_open(struct hci_dev
*hdev
)
112 static int btqcomsmd_close(struct hci_dev
*hdev
)
117 static int btqcomsmd_setup(struct hci_dev
*hdev
)
119 struct btqcomsmd
*btq
= hci_get_drvdata(hdev
);
123 skb
= __hci_cmd_sync(hdev
, HCI_OP_RESET
, 0, NULL
, HCI_INIT_TIMEOUT
);
128 /* Devices do not have persistent storage for BD address. If no
129 * BD address has been retrieved during probe, mark the device
130 * as having an invalid BD address.
132 if (!bacmp(&btq
->bdaddr
, BDADDR_ANY
)) {
133 set_bit(HCI_QUIRK_INVALID_BDADDR
, &hdev
->quirks
);
137 /* When setting a configured BD address fails, mark the device
138 * as having an invalid BD address.
140 err
= qca_set_bdaddr_rome(hdev
, &btq
->bdaddr
);
142 set_bit(HCI_QUIRK_INVALID_BDADDR
, &hdev
->quirks
);
149 static int btqcomsmd_probe(struct platform_device
*pdev
)
151 struct btqcomsmd
*btq
;
152 struct hci_dev
*hdev
;
156 btq
= devm_kzalloc(&pdev
->dev
, sizeof(*btq
), GFP_KERNEL
);
160 wcnss
= dev_get_drvdata(pdev
->dev
.parent
);
162 btq
->acl_channel
= qcom_wcnss_open_channel(wcnss
, "APPS_RIVA_BT_ACL",
163 btqcomsmd_acl_callback
, btq
);
164 if (IS_ERR(btq
->acl_channel
))
165 return PTR_ERR(btq
->acl_channel
);
167 btq
->cmd_channel
= qcom_wcnss_open_channel(wcnss
, "APPS_RIVA_BT_CMD",
168 btqcomsmd_cmd_callback
, btq
);
169 if (IS_ERR(btq
->cmd_channel
))
170 return PTR_ERR(btq
->cmd_channel
);
172 /* The local-bd-address property is usually injected by the
173 * bootloader which has access to the allocated BD address.
175 if (!of_property_read_u8_array(pdev
->dev
.of_node
, "local-bd-address",
176 (u8
*)&btq
->bdaddr
, sizeof(bdaddr_t
))) {
177 dev_info(&pdev
->dev
, "BD address %pMR retrieved from device-tree",
181 hdev
= hci_alloc_dev();
185 hci_set_drvdata(hdev
, btq
);
187 SET_HCIDEV_DEV(hdev
, &pdev
->dev
);
190 hdev
->open
= btqcomsmd_open
;
191 hdev
->close
= btqcomsmd_close
;
192 hdev
->send
= btqcomsmd_send
;
193 hdev
->setup
= btqcomsmd_setup
;
194 hdev
->set_bdaddr
= qca_set_bdaddr_rome
;
196 ret
= hci_register_dev(hdev
);
202 platform_set_drvdata(pdev
, btq
);
207 static int btqcomsmd_remove(struct platform_device
*pdev
)
209 struct btqcomsmd
*btq
= platform_get_drvdata(pdev
);
211 hci_unregister_dev(btq
->hdev
);
212 hci_free_dev(btq
->hdev
);
214 rpmsg_destroy_ept(btq
->cmd_channel
);
215 rpmsg_destroy_ept(btq
->acl_channel
);
220 static const struct of_device_id btqcomsmd_of_match
[] = {
221 { .compatible
= "qcom,wcnss-bt", },
224 MODULE_DEVICE_TABLE(of
, btqcomsmd_of_match
);
226 static struct platform_driver btqcomsmd_driver
= {
227 .probe
= btqcomsmd_probe
,
228 .remove
= btqcomsmd_remove
,
231 .of_match_table
= btqcomsmd_of_match
,
235 module_platform_driver(btqcomsmd_driver
);
237 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
238 MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
239 MODULE_LICENSE("GPL v2");