Commit ce9db464 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents e0580b50 7d250a06
...@@ -14,6 +14,7 @@ Required properties: ...@@ -14,6 +14,7 @@ Required properties:
* "brcm,bcm4330-bt" * "brcm,bcm4330-bt"
* "brcm,bcm43438-bt" * "brcm,bcm43438-bt"
* "brcm,bcm4345c5" * "brcm,bcm4345c5"
* "brcm,bcm43540-bt"
Optional properties: Optional properties:
......
...@@ -57,6 +57,7 @@ static const struct sdio_device_id btmtksdio_table[] = { ...@@ -57,6 +57,7 @@ static const struct sdio_device_id btmtksdio_table[] = {
.driver_data = (kernel_ulong_t)&mt7668_data }, .driver_data = (kernel_ulong_t)&mt7668_data },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
#define MTK_REG_CHLPCR 0x4 /* W1S */ #define MTK_REG_CHLPCR 0x4 /* W1S */
#define C_INT_EN_SET BIT(0) #define C_INT_EN_SET BIT(0)
......
...@@ -14,19 +14,33 @@ ...@@ -14,19 +14,33 @@
#define VERSION "0.1" #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 sk_buff *skb;
struct edl_event_hdr *edl; struct edl_event_hdr *edl;
struct rome_version *ver; struct qca_btsoc_version *ver;
char cmd; char cmd;
int err = 0; 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"); 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; cmd = EDL_PATCH_VER_REQ_CMD;
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, 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)) { if (IS_ERR(skb)) {
err = PTR_ERR(skb); err = PTR_ERR(skb);
bt_dev_err(hdev, "Reading QCA version information failed (%d)", 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) ...@@ -34,7 +48,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
return err; 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); bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len);
err = -EILSEQ; err = -EILSEQ;
goto out; goto out;
...@@ -48,18 +62,21 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version) ...@@ -48,18 +62,21 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
} }
if (edl->cresp != EDL_CMD_REQ_RES_EVT || 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, bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
edl->rtype); edl->rtype);
err = -EIO; err = -EIO;
goto out; 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: 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: 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)); BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
/* QCA chipset version can be decided by patch and SoC /* 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) ...@@ -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. * and lower 2 bytes from patch will be used.
*/ */
*soc_version = (le32_to_cpu(ver->soc_id) << 16) | *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) if (*soc_version == 0)
err = -EILSEQ; err = -EILSEQ;
...@@ -121,7 +138,7 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) ...@@ -121,7 +138,7 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
} }
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd); 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 struct firmware *fw)
{ {
const u8 *data; const u8 *data;
...@@ -140,8 +157,8 @@ static void qca_tlv_check_data(struct rome_config *config, ...@@ -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("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
BT_DBG("Length\t\t : %d bytes", length); BT_DBG("Length\t\t : %d bytes", length);
config->dnld_mode = ROME_SKIP_EVT_NONE; config->dnld_mode = QCA_SKIP_EVT_NONE;
config->dnld_type = ROME_SKIP_EVT_NONE; config->dnld_type = QCA_SKIP_EVT_NONE;
switch (config->type) { switch (config->type) {
case TLV_TYPE_PATCH: case TLV_TYPE_PATCH:
...@@ -223,31 +240,45 @@ static void qca_tlv_check_data(struct rome_config *config, ...@@ -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, 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 sk_buff *skb;
struct edl_event_hdr *edl; struct edl_event_hdr *edl;
struct tlv_seg_resp *tlv_resp; struct tlv_seg_resp *tlv_resp;
u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
int err = 0; 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[0] = EDL_PATCH_TLV_REQ_CMD;
cmd[1] = seg_size; cmd[1] = seg_size;
memcpy(cmd + 2, data, 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, return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
cmd); 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, 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)) { if (IS_ERR(skb)) {
err = PTR_ERR(skb); err = PTR_ERR(skb);
bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err); bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err);
return err; return err;
} }
if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) { if (skb->len != rlen) {
bt_dev_err(hdev, "QCA TLV response size mismatch"); bt_dev_err(hdev, "QCA TLV response size mismatch");
err = -EILSEQ; err = -EILSEQ;
goto out; goto out;
...@@ -260,13 +291,19 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, ...@@ -260,13 +291,19 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
goto out; 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 || if (soc_type == QCA_WCN3991)
edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) { 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)", bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)",
edl->cresp, edl->rtype, tlv_resp->result); edl->cresp, edl->rtype, tlv_resp->result);
err = -EIO;
} }
out: out:
...@@ -301,7 +338,8 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev) ...@@ -301,7 +338,8 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
} }
static int qca_download_firmware(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 struct firmware *fw;
const u8 *segment; const u8 *segment;
...@@ -328,10 +366,10 @@ static int qca_download_firmware(struct hci_dev *hdev, ...@@ -328,10 +366,10 @@ static int qca_download_firmware(struct hci_dev *hdev,
remain -= segsize; remain -= segsize;
/* The last segment is always acked regardless download mode */ /* The last segment is always acked regardless download mode */
if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) 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, ret = qca_tlv_send_segment(hdev, segsize, segment,
config->dnld_mode); config->dnld_mode, soc_type);
if (ret) if (ret)
goto out; goto out;
...@@ -344,8 +382,8 @@ static int qca_download_firmware(struct hci_dev *hdev, ...@@ -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 * decrease the BT in initialization time. Here we will inject a command
* complete event to avoid a command timeout error message. * complete event to avoid a command timeout error message.
*/ */
if (config->dnld_type == ROME_SKIP_EVT_VSE_CC || if (config->dnld_type == QCA_SKIP_EVT_VSE_CC ||
config->dnld_type == ROME_SKIP_EVT_VSE) config->dnld_type == QCA_SKIP_EVT_VSE)
ret = qca_inject_cmd_complete_event(hdev); ret = qca_inject_cmd_complete_event(hdev);
out: out:
...@@ -382,7 +420,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, ...@@ -382,7 +420,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
enum qca_btsoc_type soc_type, u32 soc_ver, enum qca_btsoc_type soc_type, u32 soc_ver,
const char *firmware_name) const char *firmware_name)
{ {
struct rome_config config; struct qca_fw_config config;
int err; int err;
u8 rom_ver = 0; u8 rom_ver = 0;
...@@ -405,7 +443,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, ...@@ -405,7 +443,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
"qca/rampatch_%08x.bin", soc_ver); "qca/rampatch_%08x.bin", soc_ver);
} }
err = qca_download_firmware(hdev, &config); err = qca_download_firmware(hdev, &config, soc_type);
if (err < 0) { if (err < 0) {
bt_dev_err(hdev, "QCA Failed to download patch (%d)", err); bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
return err; return err;
...@@ -426,7 +464,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, ...@@ -426,7 +464,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
snprintf(config.fwname, sizeof(config.fwname), snprintf(config.fwname, sizeof(config.fwname),
"qca/nvm_%08x.bin", soc_ver); "qca/nvm_%08x.bin", soc_ver);
err = qca_download_firmware(hdev, &config); err = qca_download_firmware(hdev, &config, soc_type);
if (err < 0) { if (err < 0) {
bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err); bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
return err; return err;
......
...@@ -56,24 +56,24 @@ enum qca_baudrate { ...@@ -56,24 +56,24 @@ enum qca_baudrate {
QCA_BAUDRATE_RESERVED QCA_BAUDRATE_RESERVED
}; };
enum rome_tlv_dnld_mode { enum qca_tlv_dnld_mode {
ROME_SKIP_EVT_NONE, QCA_SKIP_EVT_NONE,
ROME_SKIP_EVT_VSE, QCA_SKIP_EVT_VSE,
ROME_SKIP_EVT_CC, QCA_SKIP_EVT_CC,
ROME_SKIP_EVT_VSE_CC QCA_SKIP_EVT_VSE_CC
}; };
enum rome_tlv_type { enum qca_tlv_type {
TLV_TYPE_PATCH = 1, TLV_TYPE_PATCH = 1,
TLV_TYPE_NVM TLV_TYPE_NVM
}; };
struct rome_config { struct qca_fw_config {
u8 type; u8 type;
char fwname[64]; char fwname[64];
uint8_t user_baud_rate; uint8_t user_baud_rate;
enum rome_tlv_dnld_mode dnld_mode; enum qca_tlv_dnld_mode dnld_mode;
enum rome_tlv_dnld_mode dnld_type; enum qca_tlv_dnld_mode dnld_type;
}; };
struct edl_event_hdr { struct edl_event_hdr {
...@@ -82,10 +82,10 @@ struct edl_event_hdr { ...@@ -82,10 +82,10 @@ struct edl_event_hdr {
__u8 data[0]; __u8 data[0];
} __packed; } __packed;
struct rome_version { struct qca_btsoc_version {
__le32 product_id; __le32 product_id;
__le16 patch_ver; __le16 patch_ver;
__le16 rome_ver; __le16 rom_ver;
__le32 soc_id; __le32 soc_id;
} __packed; } __packed;
...@@ -125,6 +125,7 @@ enum qca_btsoc_type { ...@@ -125,6 +125,7 @@ enum qca_btsoc_type {
QCA_AR3002, QCA_AR3002,
QCA_ROME, QCA_ROME,
QCA_WCN3990, QCA_WCN3990,
QCA_WCN3991,
QCA_WCN3998, QCA_WCN3998,
}; };
...@@ -134,12 +135,14 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr); ...@@ -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, int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
enum qca_btsoc_type soc_type, u32 soc_ver, enum qca_btsoc_type soc_type, u32 soc_ver,
const char *firmware_name); 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_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev); int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type) 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 #else
...@@ -155,7 +158,8 @@ static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, ...@@ -155,7 +158,8 @@ static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
return -EOPNOTSUPP; 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; return -EOPNOTSUPP;
} }
......
...@@ -778,7 +778,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, ...@@ -778,7 +778,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
rtl_dev_dbg(hdev, "skipping config entry 0x%x (len %u)", rtl_dev_dbg(hdev, "skipping config entry 0x%x (len %u)",
le16_to_cpu(entry->offset), entry->len); le16_to_cpu(entry->offset), entry->len);
break; break;
}; }
i += sizeof(*entry) + entry->len; i += sizeof(*entry) + entry->len;
} }
......
...@@ -1424,6 +1424,7 @@ static const struct of_device_id bcm_bluetooth_of_match[] = { ...@@ -1424,6 +1424,7 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
{ .compatible = "brcm,bcm4345c5" }, { .compatible = "brcm,bcm4345c5" },
{ .compatible = "brcm,bcm4330-bt" }, { .compatible = "brcm,bcm4330-bt" },
{ .compatible = "brcm,bcm43438-bt" }, { .compatible = "brcm,bcm43438-bt" },
{ .compatible = "brcm,bcm43540-bt" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match); 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) ...@@ -591,6 +591,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
if (*ptr == 0xc0) { if (*ptr == 0xc0) {
BT_ERR("Short BCSP packet"); BT_ERR("Short BCSP packet");
kfree_skb(bcsp->rx_skb); kfree_skb(bcsp->rx_skb);
bcsp->rx_skb = NULL;
bcsp->rx_state = BCSP_W4_PKT_START; bcsp->rx_state = BCSP_W4_PKT_START;
bcsp->rx_count = 0; bcsp->rx_count = 0;
} else } else
...@@ -606,6 +607,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) ...@@ -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]) { bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
BT_ERR("Error in BCSP hdr checksum"); BT_ERR("Error in BCSP hdr checksum");
kfree_skb(bcsp->rx_skb); kfree_skb(bcsp->rx_skb);
bcsp->rx_skb = NULL;
bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
bcsp->rx_count = 0; bcsp->rx_count = 0;
continue; continue;
...@@ -630,6 +632,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) ...@@ -630,6 +632,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
bscp_get_crc(bcsp)); bscp_get_crc(bcsp));
kfree_skb(bcsp->rx_skb); kfree_skb(bcsp->rx_skb);
bcsp->rx_skb = NULL;
bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
bcsp->rx_count = 0; bcsp->rx_count = 0;
continue; continue;
......
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
#define HCI_MAX_IBS_SIZE 10 #define HCI_MAX_IBS_SIZE 10
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100 #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 #define CMD_TRANS_TIMEOUT_MS 100
/* susclk rate */ /* susclk rate */
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
enum qca_flags { enum qca_flags {
QCA_IBS_ENABLED, QCA_IBS_ENABLED,
QCA_DROP_VENDOR_EVENT, QCA_DROP_VENDOR_EVENT,
QCA_SUSPENDING,
}; };
/* HCI_IBS transmit side sleep protocol states */ /* HCI_IBS transmit side sleep protocol states */
...@@ -100,6 +102,7 @@ struct qca_data { ...@@ -100,6 +102,7 @@ struct qca_data {
struct work_struct ws_tx_vote_off; struct work_struct ws_tx_vote_off;
unsigned long flags; unsigned long flags;
struct completion drop_ev_comp; struct completion drop_ev_comp;
wait_queue_head_t suspend_wait_q;
/* For debugging purpose */ /* For debugging purpose */
u64 ibs_sent_wacks; u64 ibs_sent_wacks;
...@@ -437,6 +440,12 @@ static void hci_ibs_wake_retrans_timeout(struct timer_list *t) ...@@ -437,6 +440,12 @@ static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
spin_lock_irqsave_nested(&qca->hci_ibs_lock, spin_lock_irqsave_nested(&qca->hci_ibs_lock,
flags, SINGLE_DEPTH_NESTING); 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) { switch (qca->tx_ibs_state) {
case HCI_IBS_TX_WAKING: case HCI_IBS_TX_WAKING:
/* No WAKE_ACK, retransmit WAKE */ /* No WAKE_ACK, retransmit WAKE */
...@@ -496,6 +505,8 @@ static int qca_open(struct hci_uart *hu) ...@@ -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_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_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
init_waitqueue_head(&qca->suspend_wait_q);
qca->hu = hu; qca->hu = hu;
init_completion(&qca->drop_ev_comp); init_completion(&qca->drop_ev_comp);
...@@ -532,7 +543,7 @@ static int qca_open(struct hci_uart *hu) ...@@ -532,7 +543,7 @@ static int qca_open(struct hci_uart *hu)
qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS; qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0); 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", BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
qca->tx_idle_delay, qca->wake_retrans); qca->tx_idle_delay, qca->wake_retrans);
...@@ -647,6 +658,12 @@ static void device_want_to_wakeup(struct hci_uart *hu) ...@@ -647,6 +658,12 @@ static void device_want_to_wakeup(struct hci_uart *hu)
qca->ibs_recv_wakes++; 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) { switch (qca->rx_ibs_state) {
case HCI_IBS_RX_ASLEEP: case HCI_IBS_RX_ASLEEP:
/* Make sure clock is on - we may have turned clock off since /* 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) ...@@ -711,6 +728,8 @@ static void device_want_to_sleep(struct hci_uart *hu)
break; break;
} }
wake_up_interruptible(&qca->suspend_wait_q);
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
} }
...@@ -728,6 +747,12 @@ static void device_woke_up(struct hci_uart *hu) ...@@ -728,6 +747,12 @@ static void device_woke_up(struct hci_uart *hu)
qca->ibs_recv_wacks++; 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) { switch (qca->tx_ibs_state) {
case HCI_IBS_TX_AWAKE: case HCI_IBS_TX_AWAKE:
/* Expect one if we send 2 WAKEs */ /* Expect one if we send 2 WAKEs */
...@@ -780,8 +805,10 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) ...@@ -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 /* Don't go to sleep in middle of patch download or
* Out-Of-Band(GPIOs control) sleep is selected. * 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); skb_queue_tail(&qca->txq, skb);
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
return 0; return 0;
...@@ -1261,7 +1288,7 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1261,7 +1288,7 @@ static int qca_setup(struct hci_uart *hu)
if (ret) if (ret)
return ret; return ret;
ret = qca_read_soc_version(hdev, &soc_ver); ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
if (ret) if (ret)
return ret; return ret;
} else { } else {
...@@ -1281,7 +1308,7 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1281,7 +1308,7 @@ static int qca_setup(struct hci_uart *hu)
if (!qca_is_wcn399x(soc_type)) { if (!qca_is_wcn399x(soc_type)) {
/* Get QCA version information */ /* Get QCA version information */
ret = qca_read_soc_version(hdev, &soc_ver); ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1339,6 +1366,17 @@ static const struct qca_vreg_data qca_soc_data_wcn3990 = { ...@@ -1339,6 +1366,17 @@ static const struct qca_vreg_data qca_soc_data_wcn3990 = {
.num_vregs = 4, .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 = { static const struct qca_vreg_data qca_soc_data_wcn3998 = {
.soc_type = QCA_WCN3998, .soc_type = QCA_WCN3998,
.vregs = (struct qca_vreg []) { .vregs = (struct qca_vreg []) {
...@@ -1539,9 +1577,103 @@ static void qca_serdev_remove(struct serdev_device *serdev) ...@@ -1539,9 +1577,103 @@ static void qca_serdev_remove(struct serdev_device *serdev)
hci_uart_unregister_device(&qcadev->serdev_hu); 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[] = { static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,qca6174-bt" }, { .compatible = "qcom,qca6174-bt" },
{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990}, { .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}, { .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
{ /* sentinel */ } { /* sentinel */ }
}; };
...@@ -1553,6 +1685,7 @@ static struct serdev_device_driver qca_serdev_driver = { ...@@ -1553,6 +1685,7 @@ static struct serdev_device_driver qca_serdev_driver = {
.driver = { .driver = {
.name = "hci_uart_qca", .name = "hci_uart_qca",
.of_match_table = qca_bluetooth_of_match, .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) ...@@ -904,9 +904,9 @@ static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
{ {
struct adv_info *adv_instance; struct adv_info *adv_instance;
/* Ignore instance 0 */ /* Instance 0x00 always set local name */
if (instance == 0x00) if (instance == 0x00)
return 0; return 1;
adv_instance = hci_find_adv_instance(hdev, instance); adv_instance = hci_find_adv_instance(hdev, instance);
if (!adv_instance) if (!adv_instance)
...@@ -923,9 +923,9 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev) ...@@ -923,9 +923,9 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
u8 instance = hdev->cur_adv_instance; u8 instance = hdev->cur_adv_instance;
struct adv_info *adv_instance; struct adv_info *adv_instance;
/* Ignore instance 0 */ /* Instance 0x00 always set local name */
if (instance == 0x00) if (instance == 0x00)
return 0; return 1;
adv_instance = hci_find_adv_instance(hdev, instance); adv_instance = hci_find_adv_instance(hdev, instance);
if (!adv_instance) if (!adv_instance)
...@@ -1273,6 +1273,14 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) ...@@ -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); 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 /* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags. * and limited discoverable flags.
*/ */
...@@ -1305,6 +1313,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) ...@@ -1305,6 +1313,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
} }
} }
skip_flags:
if (adv_instance) { if (adv_instance) {
memcpy(ptr, adv_instance->adv_data, memcpy(ptr, adv_instance->adv_data,
adv_instance->adv_data_len); adv_instance->adv_data_len);
...@@ -1690,7 +1699,7 @@ int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance) ...@@ -1690,7 +1699,7 @@ int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance)
* scheduling it. * scheduling it.
*/ */
if (adv_instance && adv_instance->duration) { 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 */ /* Time = N * 10 ms */
adv_set->duration = cpu_to_le16(duration / 10); adv_set->duration = cpu_to_le16(duration / 10);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment