diff options
Diffstat (limited to 'drivers/bluetooth/btqca.c')
-rw-r--r-- | drivers/bluetooth/btqca.c | 123 |
1 files changed, 67 insertions, 56 deletions
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 8219816c54a0..ec9e03a6b778 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -27,7 +27,7 @@ #define VERSION "0.1" -static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) +int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version) { struct sk_buff *skb; struct edl_event_hdr *edl; @@ -35,36 +35,35 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) char cmd; int err = 0; - BT_DBG("%s: ROME Patch Version Request", hdev->name); + bt_dev_dbg(hdev, "QCA Version Request"); cmd = EDL_PATCH_VER_REQ_CMD; skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, - &cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); + &cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name, - err); + bt_dev_err(hdev, "Reading QCA version information failed (%d)", + err); return err; } if (skb->len != sizeof(*edl) + sizeof(*ver)) { - BT_ERR("%s: Version size mismatch len %d", hdev->name, - skb->len); + bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len); err = -EILSEQ; goto out; } edl = (struct edl_event_hdr *)(skb->data); if (!edl) { - BT_ERR("%s: TLV with no header", hdev->name); + bt_dev_err(hdev, "QCA TLV with no header"); err = -EILSEQ; goto out; } if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != EDL_APP_VER_RES_EVT) { - BT_ERR("%s: Wrong packet received %d %d", hdev->name, - edl->cresp, edl->rtype); + bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp, + edl->rtype); err = -EIO; goto out; } @@ -76,30 +75,35 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver)); BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id)); - /* ROME chipset version can be decided by patch and SoC + /* QCA chipset version can be decided by patch and SoC * version, combination with upper 2 bytes from SoC * and lower 2 bytes from patch will be used. */ - *rome_version = (le32_to_cpu(ver->soc_id) << 16) | + *soc_version = (le32_to_cpu(ver->soc_id) << 16) | (le16_to_cpu(ver->rome_ver) & 0x0000ffff); + if (*soc_version == 0) + err = -EILSEQ; out: kfree_skb(skb); + if (err) + bt_dev_err(hdev, "QCA Failed to get version (%d)", err); return err; } +EXPORT_SYMBOL_GPL(qca_read_soc_version); -static int rome_reset(struct hci_dev *hdev) +static int qca_send_reset(struct hci_dev *hdev) { struct sk_buff *skb; int err; - BT_DBG("%s: ROME HCI_RESET", hdev->name); + bt_dev_dbg(hdev, "QCA HCI_RESET"); skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Reset failed (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Reset failed (%d)", err); return err; } @@ -108,7 +112,7 @@ static int rome_reset(struct hci_dev *hdev) return 0; } -static void rome_tlv_check_data(struct rome_config *config, +static void qca_tlv_check_data(struct rome_config *config, const struct firmware *fw) { const u8 *data; @@ -207,7 +211,7 @@ static void rome_tlv_check_data(struct rome_config *config, } } -static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, +static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, const u8 *data, enum rome_tlv_dnld_mode mode) { struct sk_buff *skb; @@ -225,22 +229,22 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, cmd); skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd, - HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); + HCI_EV_VENDOR, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err); return err; } if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) { - BT_ERR("%s: TLV response size mismatch", hdev->name); + bt_dev_err(hdev, "QCA TLV response size mismatch"); err = -EILSEQ; goto out; } edl = (struct edl_event_hdr *)(skb->data); if (!edl) { - BT_ERR("%s: TLV with no header", hdev->name); + bt_dev_err(hdev, "TLV with no header"); err = -EILSEQ; goto out; } @@ -249,8 +253,8 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) { - BT_ERR("%s: TLV with error stat 0x%x rtype 0x%x (0x%x)", - hdev->name, edl->cresp, edl->rtype, tlv_resp->result); + bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)", + edl->cresp, edl->rtype, tlv_resp->result); err = -EIO; } @@ -260,23 +264,23 @@ out: return err; } -static int rome_download_firmware(struct hci_dev *hdev, +static int qca_download_firmware(struct hci_dev *hdev, struct rome_config *config) { const struct firmware *fw; const u8 *segment; int ret, remain, i = 0; - bt_dev_info(hdev, "ROME Downloading %s", config->fwname); + bt_dev_info(hdev, "QCA Downloading %s", config->fwname); ret = request_firmware(&fw, config->fwname, &hdev->dev); if (ret) { - BT_ERR("%s: Failed to request file: %s (%d)", hdev->name, - config->fwname, ret); + bt_dev_err(hdev, "QCA Failed to request file: %s (%d)", + config->fwname, ret); return ret; } - rome_tlv_check_data(config, fw); + qca_tlv_check_data(config, fw); segment = fw->data; remain = fw->size; @@ -290,7 +294,7 @@ static int rome_download_firmware(struct hci_dev *hdev, if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) config->dnld_mode = ROME_SKIP_EVT_NONE; - ret = rome_tlv_send_segment(hdev, segsize, segment, + ret = qca_tlv_send_segment(hdev, segsize, segment, config->dnld_mode); if (ret) break; @@ -314,11 +318,10 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) cmd[2] = sizeof(bdaddr_t); /* size */ memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd, - HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); + HCI_EV_VENDOR, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Change address command failed (%d)", - hdev->name, err); + bt_dev_err(hdev, "QCA Change address command failed (%d)", err); return err; } @@ -328,57 +331,65 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); -int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate) +int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + enum qca_btsoc_type soc_type, u32 soc_ver) { - u32 rome_ver = 0; struct rome_config config; int err; + u8 rom_ver; - BT_DBG("%s: ROME setup on UART", hdev->name); + bt_dev_dbg(hdev, "QCA setup on UART"); config.user_baud_rate = baudrate; - /* Get ROME version information */ - err = rome_patch_ver_req(hdev, &rome_ver); - if (err < 0 || rome_ver == 0) { - BT_ERR("%s: Failed to get version 0x%x", hdev->name, err); - return err; - } - - bt_dev_info(hdev, "ROME controller version 0x%08x", rome_ver); - /* Download rampatch file */ config.type = TLV_TYPE_PATCH; - snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin", - rome_ver); - err = rome_download_firmware(hdev, &config); + if (soc_type == QCA_WCN3990) { + /* Firmware files to download are based on ROM version. + * ROM version is derived from last two bytes of soc_ver. + */ + rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | + (soc_ver & 0x0000000f); + snprintf(config.fwname, sizeof(config.fwname), + "qca/crbtfw%02x.tlv", rom_ver); + } else { + snprintf(config.fwname, sizeof(config.fwname), + "qca/rampatch_%08x.bin", soc_ver); + } + + err = qca_download_firmware(hdev, &config); if (err < 0) { - BT_ERR("%s: Failed to download patch (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to download patch (%d)", err); return err; } /* Download NVM configuration */ config.type = TLV_TYPE_NVM; - snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin", - rome_ver); - err = rome_download_firmware(hdev, &config); + if (soc_type == QCA_WCN3990) + snprintf(config.fwname, sizeof(config.fwname), + "qca/crnv%02x.bin", rom_ver); + else + snprintf(config.fwname, sizeof(config.fwname), + "qca/nvm_%08x.bin", soc_ver); + + err = qca_download_firmware(hdev, &config); if (err < 0) { - BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err); return err; } /* Perform HCI reset */ - err = rome_reset(hdev); + err = qca_send_reset(hdev); if (err < 0) { - BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err); return err; } - bt_dev_info(hdev, "ROME setup on UART is completed"); + bt_dev_info(hdev, "QCA setup on UART is completed"); return 0; } -EXPORT_SYMBOL_GPL(qca_uart_setup_rome); +EXPORT_SYMBOL_GPL(qca_uart_setup); MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); |