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 return btqcomsmd_recv(btq
->hdev
, HCI_EVENT_PKT
, data
, count
);
71 static int btqcomsmd_send(struct hci_dev
*hdev
, struct sk_buff
*skb
)
73 struct btqcomsmd
*btq
= hci_get_drvdata(hdev
);
76 switch (hci_skb_pkt_type(skb
)) {
78 ret
= rpmsg_send(btq
->acl_channel
, skb
->data
, skb
->len
);
80 hdev
->stat
.byte_tx
+= skb
->len
;
83 ret
= rpmsg_send(btq
->cmd_channel
, skb
->data
, skb
->len
);
97 static int btqcomsmd_open(struct hci_dev
*hdev
)
102 static int btqcomsmd_close(struct hci_dev
*hdev
)
107 static int btqcomsmd_setup(struct hci_dev
*hdev
)
109 struct btqcomsmd
*btq
= hci_get_drvdata(hdev
);
113 skb
= __hci_cmd_sync(hdev
, HCI_OP_RESET
, 0, NULL
, HCI_INIT_TIMEOUT
);
118 /* Devices do not have persistent storage for BD address. If no
119 * BD address has been retrieved during probe, mark the device
120 * as having an invalid BD address.
122 if (!bacmp(&btq
->bdaddr
, BDADDR_ANY
)) {
123 set_bit(HCI_QUIRK_INVALID_BDADDR
, &hdev
->quirks
);
127 /* When setting a configured BD address fails, mark the device
128 * as having an invalid BD address.
130 err
= qca_set_bdaddr_rome(hdev
, &btq
->bdaddr
);
132 set_bit(HCI_QUIRK_INVALID_BDADDR
, &hdev
->quirks
);
139 static int btqcomsmd_probe(struct platform_device
*pdev
)
141 struct btqcomsmd
*btq
;
142 struct hci_dev
*hdev
;
146 btq
= devm_kzalloc(&pdev
->dev
, sizeof(*btq
), GFP_KERNEL
);
150 wcnss
= dev_get_drvdata(pdev
->dev
.parent
);
152 btq
->acl_channel
= qcom_wcnss_open_channel(wcnss
, "APPS_RIVA_BT_ACL",
153 btqcomsmd_acl_callback
, btq
);
154 if (IS_ERR(btq
->acl_channel
))
155 return PTR_ERR(btq
->acl_channel
);
157 btq
->cmd_channel
= qcom_wcnss_open_channel(wcnss
, "APPS_RIVA_BT_CMD",
158 btqcomsmd_cmd_callback
, btq
);
159 if (IS_ERR(btq
->cmd_channel
))
160 return PTR_ERR(btq
->cmd_channel
);
162 /* The local-bd-address property is usually injected by the
163 * bootloader which has access to the allocated BD address.
165 if (!of_property_read_u8_array(pdev
->dev
.of_node
, "local-bd-address",
166 (u8
*)&btq
->bdaddr
, sizeof(bdaddr_t
))) {
167 dev_info(&pdev
->dev
, "BD address %pMR retrieved from device-tree",
171 hdev
= hci_alloc_dev();
175 hci_set_drvdata(hdev
, btq
);
177 SET_HCIDEV_DEV(hdev
, &pdev
->dev
);
180 hdev
->open
= btqcomsmd_open
;
181 hdev
->close
= btqcomsmd_close
;
182 hdev
->send
= btqcomsmd_send
;
183 hdev
->setup
= btqcomsmd_setup
;
184 hdev
->set_bdaddr
= qca_set_bdaddr_rome
;
186 ret
= hci_register_dev(hdev
);
192 platform_set_drvdata(pdev
, btq
);
197 static int btqcomsmd_remove(struct platform_device
*pdev
)
199 struct btqcomsmd
*btq
= platform_get_drvdata(pdev
);
201 hci_unregister_dev(btq
->hdev
);
202 hci_free_dev(btq
->hdev
);
204 rpmsg_destroy_ept(btq
->cmd_channel
);
205 rpmsg_destroy_ept(btq
->acl_channel
);
210 static const struct of_device_id btqcomsmd_of_match
[] = {
211 { .compatible
= "qcom,wcnss-bt", },
214 MODULE_DEVICE_TABLE(of
, btqcomsmd_of_match
);
216 static struct platform_driver btqcomsmd_driver
= {
217 .probe
= btqcomsmd_probe
,
218 .remove
= btqcomsmd_remove
,
221 .of_match_table
= btqcomsmd_of_match
,
225 module_platform_driver(btqcomsmd_driver
);
227 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
228 MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
229 MODULE_LICENSE("GPL v2");