diff options
-rw-r--r-- | Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt | 5 | ||||
-rw-r--r-- | drivers/bluetooth/btbcm.c | 5 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.c | 7 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.h | 11 | ||||
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 55 | ||||
-rw-r--r-- | include/net/bluetooth/hci.h | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 5 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 12 | ||||
-rw-r--r-- | net/bluetooth/hci_request.c | 5 | ||||
-rw-r--r-- | net/bluetooth/hci_request.h | 1 |
10 files changed, 80 insertions, 27 deletions
diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt index 824c0e23c544..7ef6118abd3d 100644 --- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt @@ -11,20 +11,21 @@ Required properties: - compatible: should contain one of the following: * "qcom,qca6174-bt" * "qcom,wcn3990-bt" + * "qcom,wcn3998-bt" Optional properties for compatible string qcom,qca6174-bt: - enable-gpios: gpio specifier used to enable chip - clocks: clock provided to the controller (SUSCLK_32KHZ) -Required properties for compatible string qcom,wcn3990-bt: +Required properties for compatible string qcom,wcn399x-bt: - vddio-supply: VDD_IO supply regulator handle. - vddxo-supply: VDD_XO supply regulator handle. - vddrf-supply: VDD_RF supply regulator handle. - vddch0-supply: VDD_CH0 supply regulator handle. -Optional properties for compatible string qcom,wcn3990-bt: +Optional properties for compatible string qcom,wcn399x-bt: - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 71e74ec08310..8e17963ab65a 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -34,6 +34,7 @@ #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) #define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}}) +#define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}}) #define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) @@ -70,6 +71,9 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) * The address 20:70:02:A0:00:00 indicates a BCM20702A1 controller * with no configured address. * + * The address 20:76:A0:00:56:79 indicates a BCM2076B1 controller + * with no configured address. + * * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller * with waiting for configuration state. * @@ -81,6 +85,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) */ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) || + !bacmp(&bda->bdaddr, BDADDR_BCM2076B1) || !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 612268574fc7..cc12eecd9e4d 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -336,7 +336,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, { struct rome_config config; int err; - u8 rom_ver; + u8 rom_ver = 0; bt_dev_dbg(hdev, "QCA setup on UART"); @@ -344,7 +344,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, /* Download rampatch file */ config.type = TLV_TYPE_PATCH; - if (soc_type == QCA_WCN3990) { + if (qca_is_wcn399x(soc_type)) { /* Firmware files to download are based on ROM version. * ROM version is derived from last two bytes of soc_ver. */ @@ -365,7 +365,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, /* Download NVM configuration */ config.type = TLV_TYPE_NVM; - if (soc_type == QCA_WCN3990) + if (qca_is_wcn399x(soc_type)) snprintf(config.fwname, sizeof(config.fwname), "qca/crnv%02x.bin", rom_ver); else @@ -410,6 +410,7 @@ int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(qca_set_bdaddr); + MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index 6fdc25d7bba7..4c4fe2b5b7b7 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -132,7 +132,8 @@ enum qca_btsoc_type { QCA_INVALID = -1, QCA_AR3002, QCA_ROME, - QCA_WCN3990 + QCA_WCN3990, + QCA_WCN3998, }; #if IS_ENABLED(CONFIG_BT_QCA) @@ -142,6 +143,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, enum qca_btsoc_type soc_type, u32 soc_ver); int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version); int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type) +{ + return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3998; +} #else static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) @@ -165,4 +170,8 @@ static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) return -EOPNOTSUPP; } +static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type) +{ + return false; +} #endif diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 7f75652686fe..57322c42bb2d 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -54,9 +54,6 @@ #define HCI_IBS_WAKE_ACK 0xFC #define HCI_MAX_IBS_SIZE 10 -/* Controller states */ -#define STATE_IN_BAND_SLEEP_ENABLED 1 - #define IBS_WAKE_RETRANS_TIMEOUT_MS 100 #define IBS_TX_IDLE_TIMEOUT_MS 2000 #define CMD_TRANS_TIMEOUT_MS 100 @@ -67,6 +64,10 @@ /* Controller debug log header */ #define QCA_DEBUG_HANDLE 0x2EDC +enum qca_flags { + QCA_IBS_ENABLED, +}; + /* HCI_IBS transmit side sleep protocol states */ enum tx_ibs_states { HCI_IBS_TX_ASLEEP, @@ -521,7 +522,7 @@ static int qca_open(struct hci_uart *hu) if (hu->serdev) { qcadev = serdev_device_get_drvdata(hu->serdev); - if (qcadev->btsoc_type != QCA_WCN3990) { + if (!qca_is_wcn399x(qcadev->btsoc_type)) { gpiod_set_value_cansleep(qcadev->bt_en, 1); /* Controller needs time to bootup. */ msleep(150); @@ -629,7 +630,7 @@ static int qca_close(struct hci_uart *hu) if (hu->serdev) { qcadev = serdev_device_get_drvdata(hu->serdev); - if (qcadev->btsoc_type == QCA_WCN3990) + if (qca_is_wcn399x(qcadev->btsoc_type)) qca_power_shutdown(hu); else gpiod_set_value_cansleep(qcadev->bt_en, 0); @@ -792,7 +793,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) /* Don't go to sleep in middle of patch download or * Out-Of-Band(GPIOs control) sleep is selected. */ - if (!test_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags)) { + if (!test_bit(QCA_IBS_ENABLED, &qca->flags)) { skb_queue_tail(&qca->txq, skb); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); return 0; @@ -1011,7 +1012,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); /* Give the controller time to process the request */ - if (qca_soc_type(hu) == QCA_WCN3990) + if (qca_is_wcn399x(qca_soc_type(hu))) msleep(10); else msleep(300); @@ -1087,7 +1088,7 @@ static unsigned int qca_get_speed(struct hci_uart *hu, static int qca_check_speeds(struct hci_uart *hu) { - if (qca_soc_type(hu) == QCA_WCN3990) { + if (qca_is_wcn399x(qca_soc_type(hu))) { if (!qca_get_speed(hu, QCA_INIT_SPEED) && !qca_get_speed(hu, QCA_OPER_SPEED)) return -EINVAL; @@ -1119,7 +1120,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) /* Disable flow control for wcn3990 to deassert RTS while * changing the baudrate of chip and host. */ - if (soc_type == QCA_WCN3990) + if (qca_is_wcn399x(soc_type)) hci_uart_set_flow_control(hu, true); qca_baudrate = qca_get_baudrate_value(speed); @@ -1131,7 +1132,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) host_set_baudrate(hu, speed); error: - if (soc_type == QCA_WCN3990) + if (qca_is_wcn399x(soc_type)) hci_uart_set_flow_control(hu, false); } @@ -1202,9 +1203,9 @@ static int qca_setup(struct hci_uart *hu) return ret; /* Patch downloading has to be done without IBS mode */ - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + clear_bit(QCA_IBS_ENABLED, &qca->flags); - if (soc_type == QCA_WCN3990) { + if (qca_is_wcn399x(soc_type)) { bt_dev_info(hdev, "setting up wcn3990"); /* Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute @@ -1235,7 +1236,7 @@ static int qca_setup(struct hci_uart *hu) qca_baudrate = qca_get_baudrate_value(speed); } - if (soc_type != QCA_WCN3990) { + if (!qca_is_wcn399x(soc_type)) { /* Get QCA version information */ ret = qca_read_soc_version(hdev, &soc_ver); if (ret) @@ -1246,7 +1247,7 @@ static int qca_setup(struct hci_uart *hu) /* Setup patch / NVM configurations */ ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver); if (!ret) { - set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + set_bit(QCA_IBS_ENABLED, &qca->flags); qca_debugfs_init(hdev); } else if (ret == -ENOENT) { /* No patch/nvm-config found, run with original fw/config */ @@ -1260,7 +1261,7 @@ static int qca_setup(struct hci_uart *hu) } /* Setup bdaddr */ - if (soc_type == QCA_WCN3990) + if (qca_is_wcn399x(soc_type)) hu->hdev->set_bdaddr = qca_set_bdaddr; else hu->hdev->set_bdaddr = qca_set_bdaddr_rome; @@ -1283,7 +1284,7 @@ static struct hci_uart_proto qca_proto = { .dequeue = qca_dequeue, }; -static const struct qca_vreg_data qca_soc_data = { +static const struct qca_vreg_data qca_soc_data_wcn3990 = { .soc_type = QCA_WCN3990, .vregs = (struct qca_vreg []) { { "vddio", 1800000, 1900000, 15000 }, @@ -1294,6 +1295,17 @@ static const struct qca_vreg_data qca_soc_data = { .num_vregs = 4, }; +static const struct qca_vreg_data qca_soc_data_wcn3998 = { + .soc_type = QCA_WCN3998, + .vregs = (struct qca_vreg []) { + { "vddio", 1800000, 1900000, 10000 }, + { "vddxo", 1800000, 1900000, 80000 }, + { "vddrf", 1300000, 1352000, 300000 }, + { "vddch0", 3300000, 3300000, 450000 }, + }, + .num_vregs = 4, +}; + static void qca_power_shutdown(struct hci_uart *hu) { struct qca_data *qca = hu->priv; @@ -1304,7 +1316,7 @@ static void qca_power_shutdown(struct hci_uart *hu) * data in skb's. */ spin_lock_irqsave(&qca->hci_ibs_lock, flags); - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + clear_bit(QCA_IBS_ENABLED, &qca->flags); qca_flush(hu); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); @@ -1427,8 +1439,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) qcadev->serdev_hu.serdev = serdev; data = of_device_get_match_data(&serdev->dev); serdev_device_set_drvdata(serdev, qcadev); - if (data && data->soc_type == QCA_WCN3990) { - qcadev->btsoc_type = QCA_WCN3990; + if (data && qca_is_wcn399x(data->soc_type)) { + qcadev->btsoc_type = data->soc_type; qcadev->bt_power = devm_kzalloc(&serdev->dev, sizeof(struct qca_power), GFP_KERNEL); @@ -1492,7 +1504,7 @@ static void qca_serdev_remove(struct serdev_device *serdev) { struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); - if (qcadev->btsoc_type == QCA_WCN3990) + if (qca_is_wcn399x(qcadev->btsoc_type)) qca_power_shutdown(&qcadev->serdev_hu); else clk_disable_unprepare(qcadev->susclk); @@ -1502,7 +1514,8 @@ static void qca_serdev_remove(struct serdev_device *serdev) static const struct of_device_id qca_bluetooth_of_match[] = { { .compatible = "qcom,qca6174-bt" }, - { .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data}, + { .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990}, + { .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match); diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index fbba43e9bef5..9a5330eed794 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -282,6 +282,7 @@ enum { HCI_FORCE_BREDR_SMP, HCI_FORCE_STATIC_ADDR, HCI_LL_RPA_RESOLUTION, + HCI_CMD_PENDING, __HCI_NUM_FLAGS, }; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3d9175f130b3..b81bf53c5ac4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -4381,6 +4381,9 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, return; } + /* If we reach this point this event matches the last command sent */ + hci_dev_clear_flag(hdev, HCI_CMD_PENDING); + /* If the command succeeded and there's still more commands in * this request the request is not yet complete. */ @@ -4491,6 +4494,8 @@ static void hci_cmd_work(struct work_struct *work) hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); if (hdev->sent_cmd) { + if (hci_req_status_pend(hdev)) + hci_dev_set_flag(hdev, HCI_CMD_PENDING); atomic_dec(&hdev->cmd_cnt); hci_send_frame(hdev, skb); if (test_bit(HCI_RESET, &hdev->flags)) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 66b631ab0d35..9e4fcf406d9c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3404,6 +3404,12 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, hci_req_cmd_complete(hdev, *opcode, *status, req_complete, req_complete_skb); + if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) { + bt_dev_err(hdev, + "unexpected event for opcode 0x%4.4x", *opcode); + return; + } + if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); } @@ -3511,6 +3517,12 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb, hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete, req_complete_skb); + if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) { + bt_dev_err(hdev, + "unexpected event for opcode 0x%4.4x", *opcode); + return; + } + if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); } diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index ca73d36cc149..e9a95ed65491 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -46,6 +46,11 @@ void hci_req_purge(struct hci_request *req) skb_queue_purge(&req->cmd_q); } +bool hci_req_status_pend(struct hci_dev *hdev) +{ + return hdev->req_status == HCI_REQ_PEND; +} + static int req_run(struct hci_request *req, hci_req_complete_t complete, hci_req_complete_skb_t complete_skb) { diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 692cc8b13368..55b2050cc9ff 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -37,6 +37,7 @@ struct hci_request { void hci_req_init(struct hci_request *req, struct hci_dev *hdev); void hci_req_purge(struct hci_request *req); +bool hci_req_status_pend(struct hci_dev *hdev); int hci_req_run(struct hci_request *req, hci_req_complete_t complete); int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete); void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, |