1 /* 2 * Copyright (c) 2016, Linaro Ltd. 3 * Copyright (c) 2015, Sony Mobile Communications Inc. 4 * 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. 8 * 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. 13 */ 14 15 #include <linux/module.h> 16 #include <linux/slab.h> 17 #include <linux/rpmsg.h> 18 #include <linux/of.h> 19 20 #include <linux/soc/qcom/wcnss_ctrl.h> 21 #include <linux/platform_device.h> 22 23 #include <net/bluetooth/bluetooth.h> 24 #include <net/bluetooth/hci_core.h> 25 26 #include "btqca.h" 27 28 struct btqcomsmd { 29 struct hci_dev *hdev; 30 31 bdaddr_t bdaddr; 32 struct rpmsg_endpoint *acl_channel; 33 struct rpmsg_endpoint *cmd_channel; 34 }; 35 36 static int btqcomsmd_recv(struct hci_dev *hdev, unsigned int type, 37 const void *data, size_t count) 38 { 39 struct sk_buff *skb; 40 41 /* Use GFP_ATOMIC as we're in IRQ context */ 42 skb = bt_skb_alloc(count, GFP_ATOMIC); 43 if (!skb) { 44 hdev->stat.err_rx++; 45 return -ENOMEM; 46 } 47 48 hci_skb_pkt_type(skb) = type; 49 skb_put_data(skb, data, count); 50 51 return hci_recv_frame(hdev, skb); 52 } 53 54 static int btqcomsmd_acl_callback(struct rpmsg_device *rpdev, void *data, 55 int count, void *priv, u32 addr) 56 { 57 struct btqcomsmd *btq = priv; 58 59 btq->hdev->stat.byte_rx += count; 60 return btqcomsmd_recv(btq->hdev, HCI_ACLDATA_PKT, data, count); 61 } 62 63 static int btqcomsmd_cmd_callback(struct rpmsg_device *rpdev, void *data, 64 int count, void *priv, u32 addr) 65 { 66 struct btqcomsmd *btq = priv; 67 68 btq->hdev->stat.byte_rx += count; 69 return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count); 70 } 71 72 static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb) 73 { 74 struct btqcomsmd *btq = hci_get_drvdata(hdev); 75 int ret; 76 77 switch (hci_skb_pkt_type(skb)) { 78 case HCI_ACLDATA_PKT: 79 ret = rpmsg_send(btq->acl_channel, skb->data, skb->len); 80 if (ret) { 81 hdev->stat.err_tx++; 82 break; 83 } 84 hdev->stat.acl_tx++; 85 hdev->stat.byte_tx += skb->len; 86 break; 87 case HCI_COMMAND_PKT: 88 ret = rpmsg_send(btq->cmd_channel, skb->data, skb->len); 89 if (ret) { 90 hdev->stat.err_tx++; 91 break; 92 } 93 hdev->stat.cmd_tx++; 94 hdev->stat.byte_tx += skb->len; 95 break; 96 default: 97 ret = -EILSEQ; 98 break; 99 } 100 101 if (!ret) 102 kfree_skb(skb); 103 104 return ret; 105 } 106 107 static int btqcomsmd_open(struct hci_dev *hdev) 108 { 109 return 0; 110 } 111 112 static int btqcomsmd_close(struct hci_dev *hdev) 113 { 114 return 0; 115 } 116 117 static int btqcomsmd_setup(struct hci_dev *hdev) 118 { 119 struct btqcomsmd *btq = hci_get_drvdata(hdev); 120 struct sk_buff *skb; 121 int err; 122 123 skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); 124 if (IS_ERR(skb)) 125 return PTR_ERR(skb); 126 kfree_skb(skb); 127 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. 131 */ 132 if (!bacmp(&btq->bdaddr, BDADDR_ANY)) { 133 set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); 134 return 0; 135 } 136 137 /* When setting a configured BD address fails, mark the device 138 * as having an invalid BD address. 139 */ 140 err = qca_set_bdaddr_rome(hdev, &btq->bdaddr); 141 if (err) { 142 set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); 143 return 0; 144 } 145 146 return 0; 147 } 148 149 static int btqcomsmd_probe(struct platform_device *pdev) 150 { 151 struct btqcomsmd *btq; 152 struct hci_dev *hdev; 153 void *wcnss; 154 int ret; 155 156 btq = devm_kzalloc(&pdev->dev, sizeof(*btq), GFP_KERNEL); 157 if (!btq) 158 return -ENOMEM; 159 160 wcnss = dev_get_drvdata(pdev->dev.parent); 161 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); 166 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); 171 172 /* The local-bd-address property is usually injected by the 173 * bootloader which has access to the allocated BD address. 174 */ 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", 178 &btq->bdaddr); 179 } 180 181 hdev = hci_alloc_dev(); 182 if (!hdev) 183 return -ENOMEM; 184 185 hci_set_drvdata(hdev, btq); 186 btq->hdev = hdev; 187 SET_HCIDEV_DEV(hdev, &pdev->dev); 188 189 hdev->bus = HCI_SMD; 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; 195 196 ret = hci_register_dev(hdev); 197 if (ret < 0) { 198 hci_free_dev(hdev); 199 return ret; 200 } 201 202 platform_set_drvdata(pdev, btq); 203 204 return 0; 205 } 206 207 static int btqcomsmd_remove(struct platform_device *pdev) 208 { 209 struct btqcomsmd *btq = platform_get_drvdata(pdev); 210 211 hci_unregister_dev(btq->hdev); 212 hci_free_dev(btq->hdev); 213 214 rpmsg_destroy_ept(btq->cmd_channel); 215 rpmsg_destroy_ept(btq->acl_channel); 216 217 return 0; 218 } 219 220 static const struct of_device_id btqcomsmd_of_match[] = { 221 { .compatible = "qcom,wcnss-bt", }, 222 { }, 223 }; 224 MODULE_DEVICE_TABLE(of, btqcomsmd_of_match); 225 226 static struct platform_driver btqcomsmd_driver = { 227 .probe = btqcomsmd_probe, 228 .remove = btqcomsmd_remove, 229 .driver = { 230 .name = "btqcomsmd", 231 .of_match_table = btqcomsmd_of_match, 232 }, 233 }; 234 235 module_platform_driver(btqcomsmd_driver); 236 237 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>"); 238 MODULE_DESCRIPTION("Qualcomm SMD HCI driver"); 239 MODULE_LICENSE("GPL v2"); 240