Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: linux-bluetooth 2019-11-11 Here's one more bluetooth-next pull request for the 5.5 kernel release. - Several fixes for LE advertising - Added PM support to hci_qca driver - Added support for WCN3991 SoC in hci_qca driver - Added DT bindings for BCM43540 module - A few other small cleanups/fixes ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ce9db46436
@ -14,6 +14,7 @@ Required properties:
|
||||
* "brcm,bcm4330-bt"
|
||||
* "brcm,bcm43438-bt"
|
||||
* "brcm,bcm4345c5"
|
||||
* "brcm,bcm43540-bt"
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
@ -57,6 +57,7 @@ static const struct sdio_device_id btmtksdio_table[] = {
|
||||
.driver_data = (kernel_ulong_t)&mt7668_data },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
|
||||
#define MTK_REG_CHLPCR 0x4 /* W1S */
|
||||
#define C_INT_EN_SET BIT(0)
|
||||
|
@ -14,19 +14,33 @@
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
|
||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
enum qca_btsoc_type soc_type)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
struct rome_version *ver;
|
||||
struct qca_btsoc_version *ver;
|
||||
char cmd;
|
||||
int err = 0;
|
||||
u8 event_type = HCI_EV_VENDOR;
|
||||
u8 rlen = sizeof(*edl) + sizeof(*ver);
|
||||
u8 rtype = EDL_APP_VER_RES_EVT;
|
||||
|
||||
bt_dev_dbg(hdev, "QCA Version Request");
|
||||
|
||||
/* Unlike other SoC's sending version command response as payload to
|
||||
* VSE event. WCN3991 sends version command response as a payload to
|
||||
* command complete event.
|
||||
*/
|
||||
if (soc_type == QCA_WCN3991) {
|
||||
event_type = 0;
|
||||
rlen += 1;
|
||||
rtype = EDL_PATCH_VER_REQ_CMD;
|
||||
}
|
||||
|
||||
cmd = EDL_PATCH_VER_REQ_CMD;
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
|
||||
&cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
|
||||
&cmd, event_type, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "Reading QCA version information failed (%d)",
|
||||
@ -34,7 +48,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*edl) + sizeof(*ver)) {
|
||||
if (skb->len != rlen) {
|
||||
bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len);
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
@ -48,18 +62,21 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
|
||||
}
|
||||
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
|
||||
edl->rtype != EDL_APP_VER_RES_EVT) {
|
||||
edl->rtype != rtype) {
|
||||
bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
|
||||
edl->rtype);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ver = (struct rome_version *)(edl->data);
|
||||
if (soc_type == QCA_WCN3991)
|
||||
memmove(&edl->data, &edl->data[1], sizeof(*ver));
|
||||
|
||||
ver = (struct qca_btsoc_version *)(edl->data);
|
||||
|
||||
BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
|
||||
BT_DBG("%s: Patch :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
|
||||
BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver));
|
||||
BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rom_ver));
|
||||
BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
|
||||
|
||||
/* QCA chipset version can be decided by patch and SoC
|
||||
@ -67,7 +84,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
|
||||
* and lower 2 bytes from patch will be used.
|
||||
*/
|
||||
*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
|
||||
(le16_to_cpu(ver->rome_ver) & 0x0000ffff);
|
||||
(le16_to_cpu(ver->rom_ver) & 0x0000ffff);
|
||||
if (*soc_version == 0)
|
||||
err = -EILSEQ;
|
||||
|
||||
@ -121,7 +138,7 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
|
||||
|
||||
static void qca_tlv_check_data(struct rome_config *config,
|
||||
static void qca_tlv_check_data(struct qca_fw_config *config,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
const u8 *data;
|
||||
@ -140,8 +157,8 @@ static void qca_tlv_check_data(struct rome_config *config,
|
||||
BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
|
||||
BT_DBG("Length\t\t : %d bytes", length);
|
||||
|
||||
config->dnld_mode = ROME_SKIP_EVT_NONE;
|
||||
config->dnld_type = ROME_SKIP_EVT_NONE;
|
||||
config->dnld_mode = QCA_SKIP_EVT_NONE;
|
||||
config->dnld_type = QCA_SKIP_EVT_NONE;
|
||||
|
||||
switch (config->type) {
|
||||
case TLV_TYPE_PATCH:
|
||||
@ -223,31 +240,45 @@ static void qca_tlv_check_data(struct rome_config *config,
|
||||
}
|
||||
|
||||
static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
|
||||
const u8 *data, enum rome_tlv_dnld_mode mode)
|
||||
const u8 *data, enum qca_tlv_dnld_mode mode,
|
||||
enum qca_btsoc_type soc_type)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
struct tlv_seg_resp *tlv_resp;
|
||||
u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
|
||||
int err = 0;
|
||||
u8 event_type = HCI_EV_VENDOR;
|
||||
u8 rlen = (sizeof(*edl) + sizeof(*tlv_resp));
|
||||
u8 rtype = EDL_TVL_DNLD_RES_EVT;
|
||||
|
||||
cmd[0] = EDL_PATCH_TLV_REQ_CMD;
|
||||
cmd[1] = seg_size;
|
||||
memcpy(cmd + 2, data, seg_size);
|
||||
|
||||
if (mode == ROME_SKIP_EVT_VSE_CC || mode == ROME_SKIP_EVT_VSE)
|
||||
if (mode == QCA_SKIP_EVT_VSE_CC || mode == QCA_SKIP_EVT_VSE)
|
||||
return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
|
||||
cmd);
|
||||
|
||||
/* Unlike other SoC's sending version command response as payload to
|
||||
* VSE event. WCN3991 sends version command response as a payload to
|
||||
* command complete event.
|
||||
*/
|
||||
if (soc_type == QCA_WCN3991) {
|
||||
event_type = 0;
|
||||
rlen = sizeof(*edl);
|
||||
rtype = EDL_PATCH_TLV_REQ_CMD;
|
||||
}
|
||||
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd,
|
||||
HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
|
||||
event_type, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) {
|
||||
if (skb->len != rlen) {
|
||||
bt_dev_err(hdev, "QCA TLV response size mismatch");
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
@ -260,13 +291,19 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
tlv_resp = (struct tlv_seg_resp *)(edl->data);
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) {
|
||||
bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x",
|
||||
edl->cresp, edl->rtype);
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
|
||||
edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) {
|
||||
if (soc_type == QCA_WCN3991)
|
||||
goto out;
|
||||
|
||||
tlv_resp = (struct tlv_seg_resp *)(edl->data);
|
||||
if (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;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -301,7 +338,8 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
|
||||
}
|
||||
|
||||
static int qca_download_firmware(struct hci_dev *hdev,
|
||||
struct rome_config *config)
|
||||
struct qca_fw_config *config,
|
||||
enum qca_btsoc_type soc_type)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
const u8 *segment;
|
||||
@ -328,10 +366,10 @@ static int qca_download_firmware(struct hci_dev *hdev,
|
||||
remain -= segsize;
|
||||
/* The last segment is always acked regardless download mode */
|
||||
if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT)
|
||||
config->dnld_mode = ROME_SKIP_EVT_NONE;
|
||||
config->dnld_mode = QCA_SKIP_EVT_NONE;
|
||||
|
||||
ret = qca_tlv_send_segment(hdev, segsize, segment,
|
||||
config->dnld_mode);
|
||||
config->dnld_mode, soc_type);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -344,8 +382,8 @@ static int qca_download_firmware(struct hci_dev *hdev,
|
||||
* decrease the BT in initialization time. Here we will inject a command
|
||||
* complete event to avoid a command timeout error message.
|
||||
*/
|
||||
if (config->dnld_type == ROME_SKIP_EVT_VSE_CC ||
|
||||
config->dnld_type == ROME_SKIP_EVT_VSE)
|
||||
if (config->dnld_type == QCA_SKIP_EVT_VSE_CC ||
|
||||
config->dnld_type == QCA_SKIP_EVT_VSE)
|
||||
ret = qca_inject_cmd_complete_event(hdev);
|
||||
|
||||
out:
|
||||
@ -382,7 +420,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, u32 soc_ver,
|
||||
const char *firmware_name)
|
||||
{
|
||||
struct rome_config config;
|
||||
struct qca_fw_config config;
|
||||
int err;
|
||||
u8 rom_ver = 0;
|
||||
|
||||
@ -405,7 +443,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
"qca/rampatch_%08x.bin", soc_ver);
|
||||
}
|
||||
|
||||
err = qca_download_firmware(hdev, &config);
|
||||
err = qca_download_firmware(hdev, &config, soc_type);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
|
||||
return err;
|
||||
@ -426,7 +464,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/nvm_%08x.bin", soc_ver);
|
||||
|
||||
err = qca_download_firmware(hdev, &config);
|
||||
err = qca_download_firmware(hdev, &config, soc_type);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
|
||||
return err;
|
||||
|
@ -56,24 +56,24 @@ enum qca_baudrate {
|
||||
QCA_BAUDRATE_RESERVED
|
||||
};
|
||||
|
||||
enum rome_tlv_dnld_mode {
|
||||
ROME_SKIP_EVT_NONE,
|
||||
ROME_SKIP_EVT_VSE,
|
||||
ROME_SKIP_EVT_CC,
|
||||
ROME_SKIP_EVT_VSE_CC
|
||||
enum qca_tlv_dnld_mode {
|
||||
QCA_SKIP_EVT_NONE,
|
||||
QCA_SKIP_EVT_VSE,
|
||||
QCA_SKIP_EVT_CC,
|
||||
QCA_SKIP_EVT_VSE_CC
|
||||
};
|
||||
|
||||
enum rome_tlv_type {
|
||||
enum qca_tlv_type {
|
||||
TLV_TYPE_PATCH = 1,
|
||||
TLV_TYPE_NVM
|
||||
};
|
||||
|
||||
struct rome_config {
|
||||
struct qca_fw_config {
|
||||
u8 type;
|
||||
char fwname[64];
|
||||
uint8_t user_baud_rate;
|
||||
enum rome_tlv_dnld_mode dnld_mode;
|
||||
enum rome_tlv_dnld_mode dnld_type;
|
||||
enum qca_tlv_dnld_mode dnld_mode;
|
||||
enum qca_tlv_dnld_mode dnld_type;
|
||||
};
|
||||
|
||||
struct edl_event_hdr {
|
||||
@ -82,10 +82,10 @@ struct edl_event_hdr {
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct rome_version {
|
||||
struct qca_btsoc_version {
|
||||
__le32 product_id;
|
||||
__le16 patch_ver;
|
||||
__le16 rome_ver;
|
||||
__le16 rom_ver;
|
||||
__le32 soc_id;
|
||||
} __packed;
|
||||
|
||||
@ -125,6 +125,7 @@ enum qca_btsoc_type {
|
||||
QCA_AR3002,
|
||||
QCA_ROME,
|
||||
QCA_WCN3990,
|
||||
QCA_WCN3991,
|
||||
QCA_WCN3998,
|
||||
};
|
||||
|
||||
@ -134,12 +135,14 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, u32 soc_ver,
|
||||
const char *firmware_name);
|
||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
|
||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
enum qca_btsoc_type);
|
||||
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
|
||||
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3998;
|
||||
return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3991 ||
|
||||
soc_type == QCA_WCN3998;
|
||||
}
|
||||
#else
|
||||
|
||||
@ -155,7 +158,8 @@ static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
|
||||
static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
enum qca_btsoc_type)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -778,7 +778,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
|
||||
rtl_dev_dbg(hdev, "skipping config entry 0x%x (len %u)",
|
||||
le16_to_cpu(entry->offset), entry->len);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
i += sizeof(*entry) + entry->len;
|
||||
}
|
||||
|
@ -1424,6 +1424,7 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
|
||||
{ .compatible = "brcm,bcm4345c5" },
|
||||
{ .compatible = "brcm,bcm4330-bt" },
|
||||
{ .compatible = "brcm,bcm43438-bt" },
|
||||
{ .compatible = "brcm,bcm43540-bt" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match);
|
||||
|
@ -591,6 +591,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
||||
if (*ptr == 0xc0) {
|
||||
BT_ERR("Short BCSP packet");
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
bcsp->rx_skb = NULL;
|
||||
bcsp->rx_state = BCSP_W4_PKT_START;
|
||||
bcsp->rx_count = 0;
|
||||
} else
|
||||
@ -606,6 +607,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
||||
bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
|
||||
BT_ERR("Error in BCSP hdr checksum");
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
bcsp->rx_skb = NULL;
|
||||
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
|
||||
bcsp->rx_count = 0;
|
||||
continue;
|
||||
@ -630,6 +632,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
||||
bscp_get_crc(bcsp));
|
||||
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
bcsp->rx_skb = NULL;
|
||||
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
|
||||
bcsp->rx_count = 0;
|
||||
continue;
|
||||
|
@ -43,7 +43,8 @@
|
||||
#define HCI_MAX_IBS_SIZE 10
|
||||
|
||||
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
|
||||
#define IBS_TX_IDLE_TIMEOUT_MS 2000
|
||||
#define IBS_BTSOC_TX_IDLE_TIMEOUT_MS 40
|
||||
#define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
|
||||
#define CMD_TRANS_TIMEOUT_MS 100
|
||||
|
||||
/* susclk rate */
|
||||
@ -55,6 +56,7 @@
|
||||
enum qca_flags {
|
||||
QCA_IBS_ENABLED,
|
||||
QCA_DROP_VENDOR_EVENT,
|
||||
QCA_SUSPENDING,
|
||||
};
|
||||
|
||||
/* HCI_IBS transmit side sleep protocol states */
|
||||
@ -100,6 +102,7 @@ struct qca_data {
|
||||
struct work_struct ws_tx_vote_off;
|
||||
unsigned long flags;
|
||||
struct completion drop_ev_comp;
|
||||
wait_queue_head_t suspend_wait_q;
|
||||
|
||||
/* For debugging purpose */
|
||||
u64 ibs_sent_wacks;
|
||||
@ -437,6 +440,12 @@ static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
|
||||
spin_lock_irqsave_nested(&qca->hci_ibs_lock,
|
||||
flags, SINGLE_DEPTH_NESTING);
|
||||
|
||||
/* Don't retransmit the HCI_IBS_WAKE_IND when suspending. */
|
||||
if (test_bit(QCA_SUSPENDING, &qca->flags)) {
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (qca->tx_ibs_state) {
|
||||
case HCI_IBS_TX_WAKING:
|
||||
/* No WAKE_ACK, retransmit WAKE */
|
||||
@ -496,6 +505,8 @@ static int qca_open(struct hci_uart *hu)
|
||||
INIT_WORK(&qca->ws_rx_vote_off, qca_wq_serial_rx_clock_vote_off);
|
||||
INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
|
||||
|
||||
init_waitqueue_head(&qca->suspend_wait_q);
|
||||
|
||||
qca->hu = hu;
|
||||
init_completion(&qca->drop_ev_comp);
|
||||
|
||||
@ -532,7 +543,7 @@ static int qca_open(struct hci_uart *hu)
|
||||
qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
|
||||
|
||||
timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
|
||||
qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
|
||||
qca->tx_idle_delay = IBS_HOST_TX_IDLE_TIMEOUT_MS;
|
||||
|
||||
BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
|
||||
qca->tx_idle_delay, qca->wake_retrans);
|
||||
@ -647,6 +658,12 @@ static void device_want_to_wakeup(struct hci_uart *hu)
|
||||
|
||||
qca->ibs_recv_wakes++;
|
||||
|
||||
/* Don't wake the rx up when suspending. */
|
||||
if (test_bit(QCA_SUSPENDING, &qca->flags)) {
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (qca->rx_ibs_state) {
|
||||
case HCI_IBS_RX_ASLEEP:
|
||||
/* Make sure clock is on - we may have turned clock off since
|
||||
@ -711,6 +728,8 @@ static void device_want_to_sleep(struct hci_uart *hu)
|
||||
break;
|
||||
}
|
||||
|
||||
wake_up_interruptible(&qca->suspend_wait_q);
|
||||
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
}
|
||||
|
||||
@ -728,6 +747,12 @@ static void device_woke_up(struct hci_uart *hu)
|
||||
|
||||
qca->ibs_recv_wacks++;
|
||||
|
||||
/* Don't react to the wake-up-acknowledgment when suspending. */
|
||||
if (test_bit(QCA_SUSPENDING, &qca->flags)) {
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (qca->tx_ibs_state) {
|
||||
case HCI_IBS_TX_AWAKE:
|
||||
/* Expect one if we send 2 WAKEs */
|
||||
@ -780,8 +805,10 @@ 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.
|
||||
* Don't wake the device up when suspending.
|
||||
*/
|
||||
if (!test_bit(QCA_IBS_ENABLED, &qca->flags)) {
|
||||
if (!test_bit(QCA_IBS_ENABLED, &qca->flags) ||
|
||||
test_bit(QCA_SUSPENDING, &qca->flags)) {
|
||||
skb_queue_tail(&qca->txq, skb);
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
return 0;
|
||||
@ -1261,7 +1288,7 @@ static int qca_setup(struct hci_uart *hu)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = qca_read_soc_version(hdev, &soc_ver);
|
||||
ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
@ -1281,7 +1308,7 @@ static int qca_setup(struct hci_uart *hu)
|
||||
|
||||
if (!qca_is_wcn399x(soc_type)) {
|
||||
/* Get QCA version information */
|
||||
ret = qca_read_soc_version(hdev, &soc_ver);
|
||||
ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -1339,6 +1366,17 @@ static const struct qca_vreg_data qca_soc_data_wcn3990 = {
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static const struct qca_vreg_data qca_soc_data_wcn3991 = {
|
||||
.soc_type = QCA_WCN3991,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
{ "vddio", 15000 },
|
||||
{ "vddxo", 80000 },
|
||||
{ "vddrf", 300000 },
|
||||
{ "vddch0", 450000 },
|
||||
},
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static const struct qca_vreg_data qca_soc_data_wcn3998 = {
|
||||
.soc_type = QCA_WCN3998,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
@ -1539,9 +1577,103 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
||||
hci_uart_unregister_device(&qcadev->serdev_hu);
|
||||
}
|
||||
|
||||
static int __maybe_unused qca_suspend(struct device *dev)
|
||||
{
|
||||
struct hci_dev *hdev = container_of(dev, struct hci_dev, dev);
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct qca_data *qca = hu->priv;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
u8 cmd;
|
||||
|
||||
set_bit(QCA_SUSPENDING, &qca->flags);
|
||||
|
||||
/* Device is downloading patch or doesn't support in-band sleep. */
|
||||
if (!test_bit(QCA_IBS_ENABLED, &qca->flags))
|
||||
return 0;
|
||||
|
||||
cancel_work_sync(&qca->ws_awake_device);
|
||||
cancel_work_sync(&qca->ws_awake_rx);
|
||||
|
||||
spin_lock_irqsave_nested(&qca->hci_ibs_lock,
|
||||
flags, SINGLE_DEPTH_NESTING);
|
||||
|
||||
switch (qca->tx_ibs_state) {
|
||||
case HCI_IBS_TX_WAKING:
|
||||
del_timer(&qca->wake_retrans_timer);
|
||||
/* Fall through */
|
||||
case HCI_IBS_TX_AWAKE:
|
||||
del_timer(&qca->tx_idle_timer);
|
||||
|
||||
serdev_device_write_flush(hu->serdev);
|
||||
cmd = HCI_IBS_SLEEP_IND;
|
||||
ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
|
||||
|
||||
if (ret < 0) {
|
||||
BT_ERR("Failed to send SLEEP to device");
|
||||
break;
|
||||
}
|
||||
|
||||
qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
|
||||
qca->ibs_sent_slps++;
|
||||
|
||||
qca_wq_serial_tx_clock_vote_off(&qca->ws_tx_vote_off);
|
||||
break;
|
||||
|
||||
case HCI_IBS_TX_ASLEEP:
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Spurious tx state %d", qca->tx_ibs_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
serdev_device_wait_until_sent(hu->serdev,
|
||||
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
|
||||
|
||||
/* Wait for HCI_IBS_SLEEP_IND sent by device to indicate its Tx is going
|
||||
* to sleep, so that the packet does not wake the system later.
|
||||
*/
|
||||
|
||||
ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
|
||||
qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
|
||||
msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
|
||||
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
|
||||
if (ret == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
error:
|
||||
clear_bit(QCA_SUSPENDING, &qca->flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused qca_resume(struct device *dev)
|
||||
{
|
||||
struct hci_dev *hdev = container_of(dev, struct hci_dev, dev);
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct qca_data *qca = hu->priv;
|
||||
|
||||
clear_bit(QCA_SUSPENDING, &qca->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
|
||||
|
||||
static const struct of_device_id qca_bluetooth_of_match[] = {
|
||||
{ .compatible = "qcom,qca6174-bt" },
|
||||
{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
|
||||
{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
|
||||
{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
@ -1553,6 +1685,7 @@ static struct serdev_device_driver qca_serdev_driver = {
|
||||
.driver = {
|
||||
.name = "hci_uart_qca",
|
||||
.of_match_table = qca_bluetooth_of_match,
|
||||
.pm = &qca_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -904,9 +904,9 @@ static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
|
||||
{
|
||||
struct adv_info *adv_instance;
|
||||
|
||||
/* Ignore instance 0 */
|
||||
/* Instance 0x00 always set local name */
|
||||
if (instance == 0x00)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
adv_instance = hci_find_adv_instance(hdev, instance);
|
||||
if (!adv_instance)
|
||||
@ -923,9 +923,9 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
|
||||
u8 instance = hdev->cur_adv_instance;
|
||||
struct adv_info *adv_instance;
|
||||
|
||||
/* Ignore instance 0 */
|
||||
/* Instance 0x00 always set local name */
|
||||
if (instance == 0x00)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
adv_instance = hci_find_adv_instance(hdev, instance);
|
||||
if (!adv_instance)
|
||||
@ -1273,6 +1273,14 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
|
||||
instance_flags = get_adv_instance_flags(hdev, instance);
|
||||
|
||||
/* If instance already has the flags set skip adding it once
|
||||
* again.
|
||||
*/
|
||||
if (adv_instance && eir_get_data(adv_instance->adv_data,
|
||||
adv_instance->adv_data_len, EIR_FLAGS,
|
||||
NULL))
|
||||
goto skip_flags;
|
||||
|
||||
/* The Add Advertising command allows userspace to set both the general
|
||||
* and limited discoverable flags.
|
||||
*/
|
||||
@ -1305,6 +1313,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
skip_flags:
|
||||
if (adv_instance) {
|
||||
memcpy(ptr, adv_instance->adv_data,
|
||||
adv_instance->adv_data_len);
|
||||
@ -1690,7 +1699,7 @@ int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance)
|
||||
* scheduling it.
|
||||
*/
|
||||
if (adv_instance && adv_instance->duration) {
|
||||
u16 duration = adv_instance->duration * MSEC_PER_SEC;
|
||||
u16 duration = adv_instance->timeout * MSEC_PER_SEC;
|
||||
|
||||
/* Time = N * 10 ms */
|
||||
adv_set->duration = cpu_to_le16(duration / 10);
|
||||
|
Loading…
Reference in New Issue
Block a user