root/drivers/bluetooth/btqcomsmd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. btqcomsmd_recv
  2. btqcomsmd_acl_callback
  3. btqcomsmd_cmd_callback
  4. btqcomsmd_send
  5. btqcomsmd_open
  6. btqcomsmd_close
  7. btqcomsmd_setup
  8. btqcomsmd_probe
  9. btqcomsmd_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2016, Linaro Ltd.
   4  * Copyright (c) 2015, Sony Mobile Communications Inc.
   5  */
   6 
   7 #include <linux/module.h>
   8 #include <linux/slab.h>
   9 #include <linux/rpmsg.h>
  10 #include <linux/of.h>
  11 
  12 #include <linux/soc/qcom/wcnss_ctrl.h>
  13 #include <linux/platform_device.h>
  14 
  15 #include <net/bluetooth/bluetooth.h>
  16 #include <net/bluetooth/hci_core.h>
  17 
  18 #include "btqca.h"
  19 
  20 struct btqcomsmd {
  21         struct hci_dev *hdev;
  22 
  23         struct rpmsg_endpoint *acl_channel;
  24         struct rpmsg_endpoint *cmd_channel;
  25 };
  26 
  27 static int btqcomsmd_recv(struct hci_dev *hdev, unsigned int type,
  28                            const void *data, size_t count)
  29 {
  30         struct sk_buff *skb;
  31 
  32         /* Use GFP_ATOMIC as we're in IRQ context */
  33         skb = bt_skb_alloc(count, GFP_ATOMIC);
  34         if (!skb) {
  35                 hdev->stat.err_rx++;
  36                 return -ENOMEM;
  37         }
  38 
  39         hci_skb_pkt_type(skb) = type;
  40         skb_put_data(skb, data, count);
  41 
  42         return hci_recv_frame(hdev, skb);
  43 }
  44 
  45 static int btqcomsmd_acl_callback(struct rpmsg_device *rpdev, void *data,
  46                                   int count, void *priv, u32 addr)
  47 {
  48         struct btqcomsmd *btq = priv;
  49 
  50         btq->hdev->stat.byte_rx += count;
  51         return btqcomsmd_recv(btq->hdev, HCI_ACLDATA_PKT, data, count);
  52 }
  53 
  54 static int btqcomsmd_cmd_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_EVENT_PKT, data, count);
  61 }
  62 
  63 static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
  64 {
  65         struct btqcomsmd *btq = hci_get_drvdata(hdev);
  66         int ret;
  67 
  68         switch (hci_skb_pkt_type(skb)) {
  69         case HCI_ACLDATA_PKT:
  70                 ret = rpmsg_send(btq->acl_channel, skb->data, skb->len);
  71                 if (ret) {
  72                         hdev->stat.err_tx++;
  73                         break;
  74                 }
  75                 hdev->stat.acl_tx++;
  76                 hdev->stat.byte_tx += skb->len;
  77                 break;
  78         case HCI_COMMAND_PKT:
  79                 ret = rpmsg_send(btq->cmd_channel, skb->data, skb->len);
  80                 if (ret) {
  81                         hdev->stat.err_tx++;
  82                         break;
  83                 }
  84                 hdev->stat.cmd_tx++;
  85                 hdev->stat.byte_tx += skb->len;
  86                 break;
  87         default:
  88                 ret = -EILSEQ;
  89                 break;
  90         }
  91 
  92         if (!ret)
  93                 kfree_skb(skb);
  94 
  95         return ret;
  96 }
  97 
  98 static int btqcomsmd_open(struct hci_dev *hdev)
  99 {
 100         return 0;
 101 }
 102 
 103 static int btqcomsmd_close(struct hci_dev *hdev)
 104 {
 105         return 0;
 106 }
 107 
 108 static int btqcomsmd_setup(struct hci_dev *hdev)
 109 {
 110         struct sk_buff *skb;
 111 
 112         skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
 113         if (IS_ERR(skb))
 114                 return PTR_ERR(skb);
 115         kfree_skb(skb);
 116 
 117         /* Devices do not have persistent storage for BD address. Retrieve
 118          * it from the firmware node property.
 119          */
 120         set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
 121 
 122         return 0;
 123 }
 124 
 125 static int btqcomsmd_probe(struct platform_device *pdev)
 126 {
 127         struct btqcomsmd *btq;
 128         struct hci_dev *hdev;
 129         void *wcnss;
 130         int ret;
 131 
 132         btq = devm_kzalloc(&pdev->dev, sizeof(*btq), GFP_KERNEL);
 133         if (!btq)
 134                 return -ENOMEM;
 135 
 136         wcnss = dev_get_drvdata(pdev->dev.parent);
 137 
 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);
 142 
 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);
 147 
 148         hdev = hci_alloc_dev();
 149         if (!hdev)
 150                 return -ENOMEM;
 151 
 152         hci_set_drvdata(hdev, btq);
 153         btq->hdev = hdev;
 154         SET_HCIDEV_DEV(hdev, &pdev->dev);
 155 
 156         hdev->bus = HCI_SMD;
 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;
 162 
 163         ret = hci_register_dev(hdev);
 164         if (ret < 0) {
 165                 hci_free_dev(hdev);
 166                 return ret;
 167         }
 168 
 169         platform_set_drvdata(pdev, btq);
 170 
 171         return 0;
 172 }
 173 
 174 static int btqcomsmd_remove(struct platform_device *pdev)
 175 {
 176         struct btqcomsmd *btq = platform_get_drvdata(pdev);
 177 
 178         hci_unregister_dev(btq->hdev);
 179         hci_free_dev(btq->hdev);
 180 
 181         rpmsg_destroy_ept(btq->cmd_channel);
 182         rpmsg_destroy_ept(btq->acl_channel);
 183 
 184         return 0;
 185 }
 186 
 187 static const struct of_device_id btqcomsmd_of_match[] = {
 188         { .compatible = "qcom,wcnss-bt", },
 189         { },
 190 };
 191 MODULE_DEVICE_TABLE(of, btqcomsmd_of_match);
 192 
 193 static struct platform_driver btqcomsmd_driver = {
 194         .probe = btqcomsmd_probe,
 195         .remove = btqcomsmd_remove,
 196         .driver  = {
 197                 .name  = "btqcomsmd",
 198                 .of_match_table = btqcomsmd_of_match,
 199         },
 200 };
 201 
 202 module_platform_driver(btqcomsmd_driver);
 203 
 204 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
 205 MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
 206 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */