diff options
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btbcm.c | 14 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_drv.h | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 43 | ||||
-rw-r--r-- | drivers/bluetooth/btmtkuart.c | 538 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.c | 19 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.h | 8 | ||||
-rw-r--r-- | drivers/bluetooth/btqcomsmd.c | 31 | ||||
-rw-r--r-- | drivers/bluetooth/btrtl.c | 10 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 157 | ||||
-rw-r--r-- | drivers/bluetooth/h4_recv.h | 7 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcm.c | 134 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h4.c | 4 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h5.c | 81 | ||||
-rw-r--r-- | drivers/bluetooth/hci_intel.c | 20 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 24 | ||||
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 121 | ||||
-rw-r--r-- | drivers/bluetooth/hci_serdev.c | 3 |
18 files changed, 1011 insertions, 209 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 845b0314ce3a..7b2e76e7f22f 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -336,7 +336,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8997. + Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8977/8997. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -350,7 +350,7 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8997 + devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8977/SD8997 chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index e3e4d929e74f..d5d6e6e5da3b 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -33,6 +33,8 @@ #define VERSION "0.1" #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) +#define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 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}}) @@ -64,15 +66,23 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller * with no configured address. * + * The address 20:70:02:A0:00:00 indicates a BCM20702A1 controller + * with no configured address. + * * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller * with waiting for configuration state. * * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller * with waiting for configuration state. + * + * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller + * with no configured address. */ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || + !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) || !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || - !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) { + !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || + !bacmp(&bda->bdaddr, BDADDR_BCM43430A0)) { bt_dev_info(hdev, "BCM: Using default device address (%pMR)", &bda->bdaddr); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); @@ -330,6 +340,8 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { { 0x2209, "BCM43430A1" }, /* 001.002.009 */ { 0x6119, "BCM4345C0" }, /* 003.001.025 */ { 0x230f, "BCM4356A2" }, /* 001.003.015 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x4217, "BCM4329B1" }, /* 002.002.023 */ { } }; diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index f0454541e5fd..fb7729779166 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -24,11 +24,9 @@ #include <linux/slab.h> #include <net/bluetooth/bluetooth.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/gfp.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index fb3d03928460..047b75ce1deb 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -62,13 +62,14 @@ static const struct of_device_id btmrvl_sdio_of_match_table[] = { static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv) { struct btmrvl_sdio_card *card = priv; + struct device *dev = &card->func->dev; struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg; - pr_info("%s: wake by bt\n", __func__); + dev_info(dev, "wake by bt\n"); cfg->wake_by_bt = true; disable_irq_nosync(irq); - pm_wakeup_event(&card->func->dev, 0); + pm_wakeup_event(dev, 0); pm_system_wakeup(); return IRQ_HANDLED; @@ -87,7 +88,7 @@ static int btmrvl_sdio_probe_of(struct device *dev, if (!dev->of_node || !of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) { - pr_err("sdio platform data not available\n"); + dev_info(dev, "sdio device tree data not available\n"); return -1; } @@ -211,6 +212,29 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { .fw_dump_end = 0xea, }; +static const struct btmrvl_sdio_card_reg btmrvl_reg_8977 = { + .cfg = 0x00, + .host_int_mask = 0x08, + .host_intstatus = 0x0c, + .card_status = 0x5c, + .sq_read_base_addr_a0 = 0xf8, + .sq_read_base_addr_a1 = 0xf9, + .card_revision = 0xc8, + .card_fw_status0 = 0xe8, + .card_fw_status1 = 0xe9, + .card_rx_len = 0xea, + .card_rx_unit = 0xeb, + .io_port_0 = 0xe4, + .io_port_1 = 0xe5, + .io_port_2 = 0xe6, + .int_read_to_clear = true, + .host_int_rsr = 0x04, + .card_misc_cfg = 0xD8, + .fw_dump_ctrl = 0xf0, + .fw_dump_start = 0xf1, + .fw_dump_end = 0xf8, +}; + static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = { .cfg = 0x00, .host_int_mask = 0x08, @@ -279,6 +303,15 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .supports_fw_dump = true, }; +static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = { + .helper = NULL, + .firmware = "mrvl/sd8977_uapsta.bin", + .reg = &btmrvl_reg_8977, + .support_pscan_win_report = true, + .sd_blksz_fw_dl = 256, + .supports_fw_dump = true, +}; + static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = { .helper = NULL, .firmware = "mrvl/sd8997_uapsta.bin", @@ -307,6 +340,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8897 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), .driver_data = (unsigned long)&btmrvl_sdio_sd8897 }, + /* Marvell SD8977 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9146), + .driver_data = (unsigned long)&btmrvl_sdio_sd8977 }, /* Marvell SD8997 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142), .driver_data = (unsigned long)&btmrvl_sdio_sd8997 }, @@ -1760,4 +1796,5 @@ MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8977_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin"); diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 4593baff2bc9..b0b680dd69f4 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -12,10 +12,15 @@ #include <linux/atomic.h> #include <linux/clk.h> #include <linux/firmware.h> +#include <linux/gpio/consumer.h> +#include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <linux/serdev.h> #include <linux/skbuff.h> @@ -24,20 +29,38 @@ #include "h4_recv.h" -#define VERSION "0.1" +#define VERSION "0.2" #define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin" +#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin" +#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin" #define MTK_STP_TLR_SIZE 2 #define BTMTKUART_TX_STATE_ACTIVE 1 #define BTMTKUART_TX_STATE_WAKEUP 2 #define BTMTKUART_TX_WAIT_VND_EVT 3 +#define BTMTKUART_REQUIRED_WAKEUP 4 + +#define BTMTKUART_FLAG_STANDALONE_HW BIT(0) enum { MTK_WMT_PATCH_DWNLD = 0x1, + MTK_WMT_TEST = 0x2, + MTK_WMT_WAKEUP = 0x3, + MTK_WMT_HIF = 0x4, MTK_WMT_FUNC_CTRL = 0x6, - MTK_WMT_RST = 0x7 + MTK_WMT_RST = 0x7, + MTK_WMT_SEMAPHORE = 0x17, +}; + +enum { + BTMTK_WMT_INVALID, + BTMTK_WMT_PATCH_UNDONE, + BTMTK_WMT_PATCH_DONE, + BTMTK_WMT_ON_UNDONE, + BTMTK_WMT_ON_DONE, + BTMTK_WMT_ON_PROGRESS, }; struct mtk_stp_hdr { @@ -46,6 +69,11 @@ struct mtk_stp_hdr { u8 cs; } __packed; +struct btmtkuart_data { + unsigned int flags; + const char *fwname; +}; + struct mtk_wmt_hdr { u8 dir; u8 op; @@ -58,41 +86,85 @@ struct mtk_hci_wmt_cmd { u8 data[256]; } __packed; +struct btmtk_hci_wmt_evt { + struct hci_event_hdr hhdr; + struct mtk_wmt_hdr whdr; +} __packed; + +struct btmtk_hci_wmt_evt_funcc { + struct btmtk_hci_wmt_evt hwhdr; + __be16 status; +} __packed; + +struct btmtk_tci_sleep { + u8 mode; + __le16 duration; + __le16 host_duration; + u8 host_wakeup_pin; + u8 time_compensation; +} __packed; + +struct btmtk_hci_wmt_params { + u8 op; + u8 flag; + u16 dlen; + const void *data; + u32 *status; +}; + struct btmtkuart_dev { struct hci_dev *hdev; struct serdev_device *serdev; struct clk *clk; + struct regulator *vcc; + struct gpio_desc *reset; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_runtime; + struct pinctrl_state *pins_boot; + speed_t desired_speed; + speed_t curr_speed; + struct work_struct tx_work; unsigned long tx_state; struct sk_buff_head txq; struct sk_buff *rx_skb; + struct sk_buff *evt_skb; u8 stp_pad[6]; u8 stp_cursor; u16 stp_dlen; + + const struct btmtkuart_data *data; }; -static int mtk_hci_wmt_sync(struct hci_dev *hdev, u8 op, u8 flag, u16 plen, - const void *param) +#define btmtkuart_is_standalone(bdev) \ + ((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW) +#define btmtkuart_is_builtin_soc(bdev) \ + !((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW) + +static int mtk_hci_wmt_sync(struct hci_dev *hdev, + struct btmtk_hci_wmt_params *wmt_params) { struct btmtkuart_dev *bdev = hci_get_drvdata(hdev); + struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc; + u32 hlen, status = BTMTK_WMT_INVALID; + struct btmtk_hci_wmt_evt *wmt_evt; struct mtk_hci_wmt_cmd wc; struct mtk_wmt_hdr *hdr; - u32 hlen; int err; - hlen = sizeof(*hdr) + plen; + hlen = sizeof(*hdr) + wmt_params->dlen; if (hlen > 255) return -EINVAL; hdr = (struct mtk_wmt_hdr *)&wc; hdr->dir = 1; - hdr->op = op; - hdr->dlen = cpu_to_le16(plen + 1); - hdr->flag = flag; - memcpy(wc.data, param, plen); + hdr->op = wmt_params->op; + hdr->dlen = cpu_to_le16(wmt_params->dlen + 1); + hdr->flag = wmt_params->flag; + memcpy(wc.data, wmt_params->data, wmt_params->dlen); set_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state); @@ -107,7 +179,7 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, u8 op, u8 flag, u16 plen, * Complete as with usual HCI command flow control. * * After sending the command, wait for BTMTKUART_TX_WAIT_VND_EVT - * state to be cleared. The driver speicfic event receive routine + * state to be cleared. The driver specific event receive routine * will clear that state and with that indicate completion of the * WMT command. */ @@ -115,26 +187,63 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, u8 op, u8 flag, u16 plen, TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT); if (err == -EINTR) { bt_dev_err(hdev, "Execution of wmt command interrupted"); + clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state); return err; } if (err) { bt_dev_err(hdev, "Execution of wmt command timed out"); + clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state); return -ETIMEDOUT; } - return 0; + /* Parse and handle the return WMT event */ + wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data; + if (wmt_evt->whdr.op != hdr->op) { + bt_dev_err(hdev, "Wrong op received %d expected %d", + wmt_evt->whdr.op, hdr->op); + err = -EIO; + goto err_free_skb; + } + + switch (wmt_evt->whdr.op) { + case MTK_WMT_SEMAPHORE: + if (wmt_evt->whdr.flag == 2) + status = BTMTK_WMT_PATCH_UNDONE; + else + status = BTMTK_WMT_PATCH_DONE; + break; + case MTK_WMT_FUNC_CTRL: + wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt; + if (be16_to_cpu(wmt_evt_funcc->status) == 0x404) + status = BTMTK_WMT_ON_DONE; + else if (be16_to_cpu(wmt_evt_funcc->status) == 0x420) + status = BTMTK_WMT_ON_PROGRESS; + else + status = BTMTK_WMT_ON_UNDONE; + break; + } + + if (wmt_params->status) + *wmt_params->status = status; + +err_free_skb: + kfree_skb(bdev->evt_skb); + bdev->evt_skb = NULL; + + return err; } -static int mtk_setup_fw(struct hci_dev *hdev) +static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname) { + struct btmtk_hci_wmt_params wmt_params; const struct firmware *fw; const u8 *fw_ptr; size_t fw_size; int err, dlen; u8 flag; - err = request_firmware(&fw, FIRMWARE_MT7622, &hdev->dev); + err = request_firmware(&fw, fwname, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load firmware file (%d)", err); return err; @@ -153,6 +262,9 @@ static int mtk_setup_fw(struct hci_dev *hdev) fw_ptr += 30; flag = 1; + wmt_params.op = MTK_WMT_PATCH_DWNLD; + wmt_params.status = NULL; + while (fw_size > 0) { dlen = min_t(int, 250, fw_size); @@ -162,18 +274,37 @@ static int mtk_setup_fw(struct hci_dev *hdev) else if (fw_size < fw->size - 30) flag = 2; - err = mtk_hci_wmt_sync(hdev, MTK_WMT_PATCH_DWNLD, flag, dlen, - fw_ptr); + wmt_params.flag = flag; + wmt_params.dlen = dlen; + wmt_params.data = fw_ptr; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); - break; + goto free_fw; } fw_size -= dlen; fw_ptr += dlen; } + wmt_params.op = MTK_WMT_RST; + wmt_params.flag = 4; + wmt_params.dlen = 0; + wmt_params.data = NULL; + wmt_params.status = NULL; + + /* Activate funciton the firmware providing to */ + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) { + bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); + goto free_fw; + } + + /* Wait a few moments for firmware activation done */ + usleep_range(10000, 12000); + free_fw: release_firmware(fw); return err; @@ -192,7 +323,20 @@ static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb) if (hdr->evt == 0xe4) hdr->evt = HCI_EV_VENDOR; + /* When someone waits for the WMT event, the skb is being cloned + * and being processed the events from there then. + */ + if (test_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state)) { + bdev->evt_skb = skb_clone(skb, GFP_KERNEL); + if (!bdev->evt_skb) { + err = -ENOMEM; + goto err_out; + } + } + err = hci_recv_frame(hdev, skb); + if (err < 0) + goto err_free_skb; if (hdr->evt == HCI_EV_VENDOR) { if (test_and_clear_bit(BTMTKUART_TX_WAIT_VND_EVT, @@ -203,6 +347,13 @@ static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb) } } + return 0; + +err_free_skb: + kfree_skb(bdev->evt_skb); + bdev->evt_skb = NULL; + +err_out: return err; } @@ -404,6 +555,23 @@ static int btmtkuart_open(struct hci_dev *hdev) goto err_open; } + if (btmtkuart_is_standalone(bdev)) { + if (bdev->curr_speed != bdev->desired_speed) + err = serdev_device_set_baudrate(bdev->serdev, + 115200); + else + err = serdev_device_set_baudrate(bdev->serdev, + bdev->desired_speed); + + if (err < 0) { + bt_dev_err(hdev, "Unable to set baudrate UART device %s", + dev_name(&bdev->serdev->dev)); + goto err_serdev_close; + } + + serdev_device_set_flow_control(bdev->serdev, false); + } + bdev->stp_cursor = 2; bdev->stp_dlen = 0; @@ -427,6 +595,8 @@ err_put_rpm: pm_runtime_put_sync(dev); err_disable_rpm: pm_runtime_disable(dev); +err_serdev_close: + serdev_device_close(bdev->serdev); err_open: return err; } @@ -465,42 +635,222 @@ static int btmtkuart_flush(struct hci_dev *hdev) return 0; } +static int btmtkuart_func_query(struct hci_dev *hdev) +{ + struct btmtk_hci_wmt_params wmt_params; + int status, err; + u8 param = 0; + + /* Query whether the function is enabled */ + wmt_params.op = MTK_WMT_FUNC_CTRL; + wmt_params.flag = 4; + wmt_params.dlen = sizeof(param); + wmt_params.data = ¶m; + wmt_params.status = &status; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) { + bt_dev_err(hdev, "Failed to query function status (%d)", err); + return err; + } + + return status; +} + +static int btmtkuart_change_baudrate(struct hci_dev *hdev) +{ + struct btmtkuart_dev *bdev = hci_get_drvdata(hdev); + struct btmtk_hci_wmt_params wmt_params; + u32 baudrate; + u8 param; + int err; + + /* Indicate the device to enter the probe state the host is + * ready to change a new baudrate. + */ + baudrate = cpu_to_le32(bdev->desired_speed); + wmt_params.op = MTK_WMT_HIF; + wmt_params.flag = 1; + wmt_params.dlen = 4; + wmt_params.data = &baudrate; + wmt_params.status = NULL; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) { + bt_dev_err(hdev, "Failed to device baudrate (%d)", err); + return err; + } + + err = serdev_device_set_baudrate(bdev->serdev, + bdev->desired_speed); + if (err < 0) { + bt_dev_err(hdev, "Failed to set up host baudrate (%d)", + err); + return err; + } + + serdev_device_set_flow_control(bdev->serdev, false); + + /* Send a dummy byte 0xff to activate the new baudrate */ + param = 0xff; + err = serdev_device_write(bdev->serdev, ¶m, sizeof(param), + MAX_SCHEDULE_TIMEOUT); + if (err < 0 || err < sizeof(param)) + return err; + + serdev_device_wait_until_sent(bdev->serdev, 0); + + /* Wait some time for the device changing baudrate done */ + usleep_range(20000, 22000); + + /* Test the new baudrate */ + wmt_params.op = MTK_WMT_TEST; + wmt_params.flag = 7; + wmt_params.dlen = 0; + wmt_params.data = NULL; + wmt_params.status = NULL; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) { + bt_dev_err(hdev, "Failed to test new baudrate (%d)", + err); + return err; + } + + bdev->curr_speed = bdev->desired_speed; + + return 0; +} + static int btmtkuart_setup(struct hci_dev *hdev) { + struct btmtkuart_dev *bdev = hci_get_drvdata(hdev); + struct btmtk_hci_wmt_params wmt_params; + ktime_t calltime, delta, rettime; + struct btmtk_tci_sleep tci_sleep; + unsigned long long duration; + struct sk_buff *skb; + int err, status; u8 param = 0x1; - int err = 0; + + calltime = ktime_get(); + + /* Wakeup MCUSYS is required for certain devices before we start to + * do any setups. + */ + if (test_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state)) { + wmt_params.op = MTK_WMT_WAKEUP; + wmt_params.flag = 3; + wmt_params.dlen = 0; + wmt_params.data = NULL; + wmt_params.status = NULL; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) { + bt_dev_err(hdev, "Failed to wakeup the chip (%d)", err); + return err; + } + + clear_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state); + } + + if (btmtkuart_is_standalone(bdev)) + btmtkuart_change_baudrate(hdev); + + /* Query whether the firmware is already download */ + wmt_params.op = MTK_WMT_SEMAPHORE; + wmt_params.flag = 1; + wmt_params.dlen = 0; + wmt_params.data = NULL; + wmt_params.status = &status; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) { + bt_dev_err(hdev, "Failed to query firmware status (%d)", err); + return err; + } + + if (status == BTMTK_WMT_PATCH_DONE) { + bt_dev_info(hdev, "Firmware already downloaded"); + goto ignore_setup_fw; + } /* Setup a firmware which the device definitely requires */ - err = mtk_setup_fw(hdev); + err = mtk_setup_firmware(hdev, bdev->data->fwname); if (err < 0) return err; - /* Activate function the firmware providing to */ - err = mtk_hci_wmt_sync(hdev, MTK_WMT_RST, 0x4, 0, 0); - if (err < 0) { - bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); +ignore_setup_fw: + /* Query whether the device is already enabled */ + err = readx_poll_timeout(btmtkuart_func_query, hdev, status, + status < 0 || status != BTMTK_WMT_ON_PROGRESS, + 2000, 5000000); + /* -ETIMEDOUT happens */ + if (err < 0) return err; + + /* The other errors happen in btusb_mtk_func_query */ + if (status < 0) + return status; + + if (status == BTMTK_WMT_ON_DONE) { + bt_dev_info(hdev, "function already on"); + goto ignore_func_on; } /* Enable Bluetooth protocol */ - err = mtk_hci_wmt_sync(hdev, MTK_WMT_FUNC_CTRL, 0x0, sizeof(param), - ¶m); + wmt_params.op = MTK_WMT_FUNC_CTRL; + wmt_params.flag = 0; + wmt_params.dlen = sizeof(param); + wmt_params.data = ¶m; + wmt_params.status = NULL; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); return err; } +ignore_func_on: + /* Apply the low power environment setup */ + tci_sleep.mode = 0x5; + tci_sleep.duration = cpu_to_le16(0x640); + tci_sleep.host_duration = cpu_to_le16(0x640); + tci_sleep.host_wakeup_pin = 0; + tci_sleep.time_compensation = 0; + + skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + bt_dev_err(hdev, "Failed to apply low power setting (%d)", err); + return err; + } + kfree_skb(skb); + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long)ktime_to_ns(delta) >> 10; + + bt_dev_info(hdev, "Device setup in %llu usecs", duration); + return 0; } static int btmtkuart_shutdown(struct hci_dev *hdev) { + struct btmtk_hci_wmt_params wmt_params; u8 param = 0x0; int err; /* Disable the device */ - err = mtk_hci_wmt_sync(hdev, MTK_WMT_FUNC_CTRL, 0x0, sizeof(param), - ¶m); + wmt_params.op = MTK_WMT_FUNC_CTRL; + wmt_params.flag = 0; + wmt_params.dlen = sizeof(param); + wmt_params.data = ¶m; + wmt_params.status = NULL; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); return err; @@ -543,24 +893,82 @@ static int btmtkuart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) return 0; } +static int btmtkuart_parse_dt(struct serdev_device *serdev) +{ + struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); + struct device_node *node = serdev->dev.of_node; + u32 speed = 921600; + int err; + + if (btmtkuart_is_standalone(bdev)) { + of_property_read_u32(node, "current-speed", &speed); + + bdev->desired_speed = speed; + + bdev->vcc = devm_regulator_get(&serdev->dev, "vcc"); + if (IS_ERR(bdev->vcc)) { + err = PTR_ERR(bdev->vcc); + return err; + } + + bdev->pinctrl = devm_pinctrl_get(&serdev->dev); + if (IS_ERR(bdev->pinctrl)) { + err = PTR_ERR(bdev->pinctrl); + return err; + } + + bdev->pins_boot = pinctrl_lookup_state(bdev->pinctrl, + "default"); + if (IS_ERR(bdev->pins_boot)) { + err = PTR_ERR(bdev->pins_boot); + return err; + } + + bdev->pins_runtime = pinctrl_lookup_state(bdev->pinctrl, + "runtime"); + if (IS_ERR(bdev->pins_runtime)) { + err = PTR_ERR(bdev->pins_runtime); + return err; + } + + bdev->reset = devm_gpiod_get_optional(&serdev->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(bdev->reset)) { + err = PTR_ERR(bdev->reset); + return err; + } + } else if (btmtkuart_is_builtin_soc(bdev)) { + bdev->clk = devm_clk_get(&serdev->dev, "ref"); + if (IS_ERR(bdev->clk)) + return PTR_ERR(bdev->clk); + } + + return 0; +} + static int btmtkuart_probe(struct serdev_device *serdev) { struct btmtkuart_dev *bdev; struct hci_dev *hdev; + int err; bdev = devm_kzalloc(&serdev->dev, sizeof(*bdev), GFP_KERNEL); if (!bdev) return -ENOMEM; - bdev->clk = devm_clk_get(&serdev->dev, "ref"); - if (IS_ERR(bdev->clk)) - return PTR_ERR(bdev->clk); + bdev->data = of_device_get_match_data(&serdev->dev); + if (!bdev->data) + return -ENODEV; bdev->serdev = serdev; serdev_device_set_drvdata(serdev, bdev); serdev_device_set_client_ops(serdev, &btmtkuart_client_ops); + err = btmtkuart_parse_dt(serdev); + if (err < 0) + return err; + INIT_WORK(&bdev->tx_work, btmtkuart_tx_work); skb_queue_head_init(&bdev->txq); @@ -587,13 +995,54 @@ static int btmtkuart_probe(struct serdev_device *serdev) hdev->manufacturer = 70; set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); - if (hci_register_dev(hdev) < 0) { + if (btmtkuart_is_standalone(bdev)) { + /* Switch to the specific pin state for the booting requires */ + pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); + + /* Power on */ + err = regulator_enable(bdev->vcc); + if (err < 0) + return err; + + /* Reset if the reset-gpios is available otherwise the board + * -level design should be guaranteed. + */ + if (bdev->reset) { + gpiod_set_value_cansleep(bdev->reset, 1); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(bdev->reset, 0); + } + + /* Wait some time until device got ready and switch to the pin + * mode the device requires for UART transfers. + */ + msleep(50); + pinctrl_select_state(bdev->pinctrl, bdev->pins_runtime); + + /* A standalone device doesn't depends on power domain on SoC, + * so mark it as no callbacks. + */ + pm_runtime_no_callbacks(&serdev->dev); + + set_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state); + } + + err = hci_register_dev(hdev); + if (err < 0) { dev_err(&serdev->dev, "Can't register HCI device\n"); hci_free_dev(hdev); - return -ENODEV; + goto err_regulator_disable; } return 0; + +err_regulator_disable: + if (btmtkuart_is_standalone(bdev)) { + pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); + regulator_disable(bdev->vcc); + } + + return err; } static void btmtkuart_remove(struct serdev_device *serdev) @@ -601,13 +1050,34 @@ static void btmtkuart_remove(struct serdev_device *serdev) struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); struct hci_dev *hdev = bdev->hdev; + if (btmtkuart_is_standalone(bdev)) { + pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); + regulator_disable(bdev->vcc); + } + hci_unregister_dev(hdev); hci_free_dev(hdev); } +static const struct btmtkuart_data mt7622_data = { + .fwname = FIRMWARE_MT7622, +}; + +static const struct btmtkuart_data mt7663_data = { + .flags = BTMTKUART_FLAG_STANDALONE_HW, + .fwname = FIRMWARE_MT7663, +}; + +static const struct btmtkuart_data mt7668_data = { + .flags = BTMTKUART_FLAG_STANDALONE_HW, + .fwname = FIRMWARE_MT7668, +}; + #ifdef CONFIG_OF static const struct of_device_id mtk_of_match_table[] = { - { .compatible = "mediatek,mt7622-bluetooth"}, + { .compatible = "mediatek,mt7622-bluetooth", .data = &mt7622_data}, + { .compatible = "mediatek,mt7663u-bluetooth", .data = &mt7663_data}, + { .compatible = "mediatek,mt7668u-bluetooth", .data = &mt7668_data}, { } }; MODULE_DEVICE_TABLE(of, mtk_of_match_table); @@ -629,3 +1099,5 @@ MODULE_DESCRIPTION("MediaTek Bluetooth Serial driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(FIRMWARE_MT7622); +MODULE_FIRMWARE(FIRMWARE_MT7663); +MODULE_FIRMWARE(FIRMWARE_MT7668); diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index ec9e03a6b778..612268574fc7 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -391,6 +391,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, } EXPORT_SYMBOL_GPL(qca_uart_setup); +int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + int err; + + skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, bdaddr, + HCI_EV_VENDOR, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err); + return err; + } + + kfree_skb(skb); + + return 0; +} +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 0c01f375fe83..c72c56ea7480 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -20,6 +20,7 @@ #define EDL_PATCH_CMD_OPCODE (0xFC00) #define EDL_NVM_ACCESS_OPCODE (0xFC0B) +#define EDL_WRITE_BD_ADDR_OPCODE (0xFC14) #define EDL_PATCH_CMD_LEN (1) #define EDL_PATCH_VER_REQ_CMD (0x19) #define EDL_PATCH_TLV_REQ_CMD (0x1E) @@ -140,7 +141,7 @@ 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); int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version); - +int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); #else static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) @@ -159,4 +160,9 @@ static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version) return -EOPNOTSUPP; } +static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + return -EOPNOTSUPP; +} + #endif diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index 7df3eed1ef5e..e0d4c6f1d3ab 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -28,7 +28,6 @@ struct btqcomsmd { struct hci_dev *hdev; - bdaddr_t bdaddr; struct rpmsg_endpoint *acl_channel; struct rpmsg_endpoint *cmd_channel; }; @@ -116,32 +115,17 @@ static int btqcomsmd_close(struct hci_dev *hdev) static int btqcomsmd_setup(struct hci_dev *hdev) { - struct btqcomsmd *btq = hci_get_drvdata(hdev); struct sk_buff *skb; - int err; skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) return PTR_ERR(skb); kfree_skb(skb); - /* Devices do not have persistent storage for BD address. If no - * BD address has been retrieved during probe, mark the device - * as having an invalid BD address. - */ - if (!bacmp(&btq->bdaddr, BDADDR_ANY)) { - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); - return 0; - } - - /* When setting a configured BD address fails, mark the device - * as having an invalid BD address. + /* Devices do not have persistent storage for BD address. Retrieve + * it from the firmware node property. */ - err = qca_set_bdaddr_rome(hdev, &btq->bdaddr); - if (err) { - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); - return 0; - } + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); return 0; } @@ -169,15 +153,6 @@ static int btqcomsmd_probe(struct platform_device *pdev) if (IS_ERR(btq->cmd_channel)) return PTR_ERR(btq->cmd_channel); - /* The local-bd-address property is usually injected by the - * bootloader which has access to the allocated BD address. - */ - if (!of_property_read_u8_array(pdev->dev.of_node, "local-bd-address", - (u8 *)&btq->bdaddr, sizeof(bdaddr_t))) { - dev_info(&pdev->dev, "BD address %pMR retrieved from device-tree", - &btq->bdaddr); - } - hdev = hci_alloc_dev(); if (!hdev) return -ENOMEM; diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 41405de27d66..c91bba00df4e 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -552,10 +552,9 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, hdev->bus); if (!btrtl_dev->ic_info) { - rtl_dev_err(hdev, "rtl: unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x", + rtl_dev_info(hdev, "rtl: unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x", lmp_subver, hci_rev, hci_ver); - ret = -EINVAL; - goto err_free; + return btrtl_dev; } if (btrtl_dev->ic_info->has_rom_version) { @@ -610,6 +609,11 @@ int btrtl_download_firmware(struct hci_dev *hdev, * standard btusb. Once that firmware is uploaded, the subver changes * to a different value. */ + if (!btrtl_dev->ic_info) { + rtl_dev_info(hdev, "rtl: assuming no firmware upload needed\n"); + return 0; + } + switch (btrtl_dev->ic_info->lmp_subver) { case RTL_ROM_LMP_8723A: case RTL_ROM_LMP_3499: diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7439a7eb50ac..7db48ae65cd2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -29,6 +29,7 @@ #include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/suspend.h> +#include <linux/gpio/consumer.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -344,6 +345,7 @@ static const struct usb_device_id blacklist_table[] = { /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW }, { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW }, + { USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_NEW }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, @@ -438,6 +440,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { #define BTUSB_BOOTING 9 #define BTUSB_DIAG_RUNNING 10 #define BTUSB_OOB_WAKE_ENABLED 11 +#define BTUSB_HW_RESET_ACTIVE 12 struct btusb_data { struct hci_dev *hdev; @@ -475,6 +478,8 @@ struct btusb_data { struct usb_endpoint_descriptor *diag_tx_ep; struct usb_endpoint_descriptor *diag_rx_ep; + struct gpio_desc *reset_gpio; + __u8 cmdreq_type; __u8 cmdreq; @@ -488,8 +493,41 @@ struct btusb_data { int (*setup_on_usb)(struct hci_dev *hdev); int oob_wake_irq; /* irq for out-of-band wake-on-bt */ + unsigned cmd_timeout_cnt; }; + +static void btusb_intel_cmd_timeout(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct gpio_desc *reset_gpio = data->reset_gpio; + + if (++data->cmd_timeout_cnt < 5) + return; + + if (!reset_gpio) { + bt_dev_err(hdev, "No way to reset. Ignoring and continuing"); + return; + } + + /* + * Toggle the hard reset line if the platform provides one. The reset + * is going to yank the device off the USB and then replug. So doing + * once is enough. The cleanup is handled correctly on the way out + * (standard USB disconnect), and the new device is detected cleanly + * and bound to the driver again like it should be. + */ + if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) { + bt_dev_err(hdev, "last reset failed? Not resetting again"); + return; + } + + bt_dev_err(hdev, "Initiating HW reset via gpio"); + gpiod_set_value_cansleep(reset_gpio, 1); + msleep(100); + gpiod_set_value_cansleep(reset_gpio, 0); +} + static inline void btusb_free_frags(struct btusb_data *data) { unsigned long flags; @@ -1935,10 +1973,8 @@ static void btusb_intel_bootup(struct btusb_data *data, const void *ptr, if (len != sizeof(*evt)) return; - if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) { - smp_mb__after_atomic(); + if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) wake_up_bit(&data->flags, BTUSB_BOOTING); - } } static void btusb_intel_secure_send_result(struct btusb_data *data, @@ -1953,10 +1989,8 @@ static void btusb_intel_secure_send_result(struct btusb_data *data, set_bit(BTUSB_FIRMWARE_FAILED, &data->flags); if (test_and_clear_bit(BTUSB_DOWNLOADING, &data->flags) && - test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) { - smp_mb__after_atomic(); + test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) wake_up_bit(&data->flags, BTUSB_DOWNLOADING); - } } static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) @@ -2055,6 +2089,35 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) return -EILSEQ; } +static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver, + struct intel_boot_params *params, + char *fw_name, size_t len, + const char *suffix) +{ + switch (ver->hw_variant) { + case 0x0b: /* SfP */ + case 0x0c: /* WsP */ + snprintf(fw_name, len, "intel/ibt-%u-%u.%s", + le16_to_cpu(ver->hw_variant), + le16_to_cpu(params->dev_revid), + suffix); + break; + case 0x11: /* JfP */ + case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* CcP */ + snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s", + le16_to_cpu(ver->hw_variant), + le16_to_cpu(ver->hw_revision), + le16_to_cpu(ver->fw_revision), + suffix); + break; + default: + return false; + } + return true; +} + static int btusb_setup_intel_new(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2106,7 +2169,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) case 0x11: /* JfP */ case 0x12: /* ThP */ case 0x13: /* HrP */ - case 0x14: /* QnJ, IcP */ + case 0x14: /* CcP */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)", @@ -2190,23 +2253,9 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) * ibt-<hw_variant>-<hw_revision>-<fw_revision>.sfi. * */ - switch (ver.hw_variant) { - case 0x0b: /* SfP */ - case 0x0c: /* WsP */ - snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", - le16_to_cpu(ver.hw_variant), - le16_to_cpu(params.dev_revid)); - break; - case 0x11: /* JfP */ - case 0x12: /* ThP */ - case 0x13: /* HrP */ - case 0x14: /* QnJ, IcP */ - snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi", - le16_to_cpu(ver.hw_variant), - le16_to_cpu(ver.hw_revision), - le16_to_cpu(ver.fw_revision)); - break; - default: + err = btusb_setup_intel_new_get_fw_name(&ver, ¶ms, fwname, + sizeof(fwname), "sfi"); + if (!err) { bt_dev_err(hdev, "Unsupported Intel firmware naming"); return -EINVAL; } @@ -2222,23 +2271,9 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Save the DDC file name for later use to apply once the firmware * downloading is done. */ - switch (ver.hw_variant) { - case 0x0b: /* SfP */ - case 0x0c: /* WsP */ - snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc", - le16_to_cpu(ver.hw_variant), - le16_to_cpu(params.dev_revid)); - break; - case 0x11: /* JfP */ - case 0x12: /* ThP */ - case 0x13: /* HrP */ - case 0x14: /* QnJ, IcP */ - snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc", - le16_to_cpu(ver.hw_variant), - le16_to_cpu(ver.hw_revision), - le16_to_cpu(ver.fw_revision)); - break; - default: + err = btusb_setup_intel_new_get_fw_name(&ver, ¶ms, fwname, + sizeof(fwname), "ddc"); + if (!err) { bt_dev_err(hdev, "Unsupported Intel firmware naming"); return -EINVAL; } @@ -2399,6 +2434,24 @@ static int btusb_shutdown_intel(struct hci_dev *hdev) return 0; } +static int btusb_shutdown_intel_new(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + /* Send HCI Reset to the controller to stop any BT activity which + * were triggered. This will help to save power and maintain the + * sync b/w Host and controller + */ + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "HCI reset during shutdown failed"); + return PTR_ERR(skb); + } + kfree_skb(skb); + + return 0; +} + #ifdef CONFIG_PM /* Configure an out-of-band gpio as wake-up pin, if specified in device tree */ static int marvell_config_oob_wake(struct hci_dev *hdev) @@ -2864,6 +2917,8 @@ static irqreturn_t btusb_oob_wake_handler(int irq, void *priv) static const struct of_device_id btusb_match_table[] = { { .compatible = "usb1286,204e" }, + { .compatible = "usbcf3,e300" }, /* QCA6174A */ + { .compatible = "usb4ca,301a" }, /* QCA6174A (Lite-On) */ { } }; MODULE_DEVICE_TABLE(of, btusb_match_table); @@ -2887,6 +2942,7 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) return 0; } + irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler, 0, "OOB Wake-on-BT", data); if (ret) { @@ -2901,7 +2957,6 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) } data->oob_wake_irq = irq; - disable_irq(irq); bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq); return 0; } @@ -2917,6 +2972,7 @@ static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_endpoint_descriptor *ep_desc; + struct gpio_desc *reset_gpio; struct btusb_data *data; struct hci_dev *hdev; unsigned ifnum_base; @@ -3030,6 +3086,15 @@ static int btusb_probe(struct usb_interface *intf, SET_HCIDEV_DEV(hdev, &intf->dev); + reset_gpio = gpiod_get_optional(&data->udev->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) { + err = PTR_ERR(reset_gpio); + goto out_free_dev; + } else if (reset_gpio) { + data->reset_gpio = reset_gpio; + } + hdev->open = btusb_open; hdev->close = btusb_close; hdev->flush = btusb_flush; @@ -3084,6 +3149,7 @@ static int btusb_probe(struct usb_interface *intf, hdev->shutdown = btusb_shutdown_intel; hdev->set_diag = btintel_set_diag_mfg; hdev->set_bdaddr = btintel_set_bdaddr; + hdev->cmd_timeout = btusb_intel_cmd_timeout; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); @@ -3093,9 +3159,11 @@ static int btusb_probe(struct usb_interface *intf, hdev->manufacturer = 2; hdev->send = btusb_send_frame_intel; hdev->setup = btusb_setup_intel_new; + hdev->shutdown = btusb_shutdown_intel_new; hdev->hw_error = btintel_hw_error; hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; + hdev->cmd_timeout = btusb_intel_cmd_timeout; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); @@ -3228,6 +3296,8 @@ static int btusb_probe(struct usb_interface *intf, return 0; out_free_dev: + if (data->reset_gpio) + gpiod_put(data->reset_gpio); hci_free_dev(hdev); return err; } @@ -3271,6 +3341,9 @@ static void btusb_disconnect(struct usb_interface *intf) if (data->oob_wake_irq) device_init_wakeup(&data->udev->dev, false); + if (data->reset_gpio) + gpiod_put(data->reset_gpio); + hci_free_dev(hdev); } diff --git a/drivers/bluetooth/h4_recv.h b/drivers/bluetooth/h4_recv.h index b432651f8236..87ccaceadba7 100644 --- a/drivers/bluetooth/h4_recv.h +++ b/drivers/bluetooth/h4_recv.h @@ -60,12 +60,13 @@ static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev, const struct h4_recv_pkt *pkts, int pkts_count) { + /* Check for error from previous call */ + if (IS_ERR(skb)) + skb = NULL; + while (count) { int i, len; - if (!count) - break; - if (!skb) { for (i = 0; i < pkts_count; i++) { if (buffer[0] != (&pkts[i])->type) diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index ddbd8c6a0ceb..ddbe518c3e5b 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -31,6 +31,7 @@ #include <linux/property.h> #include <linux/platform_data/x86/apple.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/clk.h> #include <linux/gpio/consumer.h> #include <linux/tty.h> @@ -51,8 +52,16 @@ #define BCM_LM_DIAG_PKT 0x07 #define BCM_LM_DIAG_SIZE 63 +#define BCM_TYPE49_PKT 0x31 +#define BCM_TYPE49_SIZE 0 + +#define BCM_TYPE52_PKT 0x34 +#define BCM_TYPE52_SIZE 0 + #define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */ +#define BCM_NUM_SUPPLIES 2 + /** * struct bcm_device - device driver resources * @serdev_hu: HCI UART controller struct @@ -71,8 +80,10 @@ * @btlp: Apple ACPI method to toggle BT_WAKE pin ("Bluetooth Low Power") * @btpu: Apple ACPI method to drive BT_REG_ON pin high ("Bluetooth Power Up") * @btpd: Apple ACPI method to drive BT_REG_ON pin low ("Bluetooth Power Down") - * @clk: clock used by Bluetooth device - * @clk_enabled: whether @clk is prepared and enabled + * @txco_clk: external reference frequency clock used by Bluetooth device + * @lpo_clk: external LPO clock used by Bluetooth device + * @supplies: VBAT and VDDIO supplies used by Bluetooth device + * @res_enabled: whether clocks and supplies are prepared and enabled * @init_speed: default baudrate of Bluetooth device; * the host UART is initially set to this baudrate so that * it can configure the Bluetooth device for @oper_speed @@ -102,8 +113,10 @@ struct bcm_device { int gpio_int_idx; #endif - struct clk *clk; - bool clk_enabled; + struct clk *txco_clk; + struct clk *lpo_clk; + struct regulator_bulk_data supplies[BCM_NUM_SUPPLIES]; + bool res_enabled; u32 init_speed; u32 oper_speed; @@ -214,32 +227,59 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered) { int err; - if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled) { - err = clk_prepare_enable(dev->clk); + if (powered && !dev->res_enabled) { + err = regulator_bulk_enable(BCM_NUM_SUPPLIES, dev->supplies); if (err) return err; + + /* LPO clock needs to be 32.768 kHz */ + err = clk_set_rate(dev->lpo_clk, 32768); + if (err) { + dev_err(dev->dev, "Could not set LPO clock rate\n"); + goto err_regulator_disable; + } + + err = clk_prepare_enable(dev->lpo_clk); + if (err) + goto err_regulator_disable; + + err = clk_prepare_enable(dev->txco_clk); + if (err) + goto err_lpo_clk_disable; } err = dev->set_shutdown(dev, powered); if (err) - goto err_clk_disable; + goto err_txco_clk_disable; err = dev->set_device_wakeup(dev, powered); if (err) goto err_revert_shutdown; - if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled) - clk_disable_unprepare(dev->clk); + if (!powered && dev->res_enabled) { + clk_disable_unprepare(dev->txco_clk); + clk_disable_unprepare(dev->lpo_clk); + regulator_bulk_disable(BCM_NUM_SUPPLIES, dev->supplies); + } + + /* wait for device to power on and come out of reset */ + usleep_range(10000, 20000); - dev->clk_enabled = powered; + dev->res_enabled = powered; return 0; err_revert_shutdown: dev->set_shutdown(dev, !powered); -err_clk_disable: - if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled) - clk_disable_unprepare(dev->clk); +err_txco_clk_disable: + if (powered && !dev->res_enabled) + clk_disable_unprepare(dev->txco_clk); +err_lpo_clk_disable: + if (powered && !dev->res_enabled) + clk_disable_unprepare(dev->lpo_clk); +err_regulator_disable: + if (powered && !dev->res_enabled) + regulator_bulk_disable(BCM_NUM_SUPPLIES, dev->supplies); return err; } @@ -561,12 +601,28 @@ finalize: .lsize = 0, \ .maxlen = BCM_NULL_SIZE +#define BCM_RECV_TYPE49 \ + .type = BCM_TYPE49_PKT, \ + .hlen = BCM_TYPE49_SIZE, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = BCM_TYPE49_SIZE + +#define BCM_RECV_TYPE52 \ + .type = BCM_TYPE52_PKT, \ + .hlen = BCM_TYPE52_SIZE, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = BCM_TYPE52_SIZE + static const struct h4_recv_pkt bcm_recv_pkts[] = { { H4_RECV_ACL, .recv = hci_recv_frame }, { H4_RECV_SCO, .recv = hci_recv_frame }, { H4_RECV_EVENT, .recv = hci_recv_frame }, { BCM_RECV_LM_DIAG, .recv = hci_recv_diag }, { BCM_RECV_NULL, .recv = hci_recv_diag }, + { BCM_RECV_TYPE49, .recv = hci_recv_diag }, + { BCM_RECV_TYPE52, .recv = hci_recv_diag }, }; static int bcm_recv(struct hci_uart *hu, const void *data, int count) @@ -896,16 +952,57 @@ static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered) return 0; } +/* Try a bunch of names for TXCO */ +static struct clk *bcm_get_txco(struct device *dev) +{ + struct clk *clk; + + /* New explicit name */ + clk = devm_clk_get(dev, "txco"); + if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) + return clk; + + /* Deprecated name */ + clk = devm_clk_get(dev, "extclk"); + if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) + return clk; + + /* Original code used no name at all */ + return devm_clk_get(dev, NULL); +} + static int bcm_get_resources(struct bcm_device *dev) { const struct dmi_system_id *dmi_id; + int err; dev->name = dev_name(dev->dev); if (x86_apple_machine && !bcm_apple_get_resources(dev)) return 0; - dev->clk = devm_clk_get(dev->dev, NULL); + dev->txco_clk = bcm_get_txco(dev->dev); + + /* Handle deferred probing */ + if (dev->txco_clk == ERR_PTR(-EPROBE_DEFER)) + return PTR_ERR(dev->txco_clk); + + /* Ignore all other errors as before */ + if (IS_ERR(dev->txco_clk)) + dev->txco_clk = NULL; + + dev->lpo_clk = devm_clk_get(dev->dev, "lpo"); + if (dev->lpo_clk == ERR_PTR(-EPROBE_DEFER)) + return PTR_ERR(dev->lpo_clk); + + if (IS_ERR(dev->lpo_clk)) + dev->lpo_clk = NULL; + + /* Check if we accidentally fetched the lpo clock twice */ + if (dev->lpo_clk && clk_is_match(dev->lpo_clk, dev->txco_clk)) { + devm_clk_put(dev->dev, dev->txco_clk); + dev->txco_clk = NULL; + } dev->device_wakeup = devm_gpiod_get_optional(dev->dev, "device-wakeup", GPIOD_OUT_LOW); @@ -920,6 +1017,13 @@ static int bcm_get_resources(struct bcm_device *dev) dev->set_device_wakeup = bcm_gpio_set_device_wakeup; dev->set_shutdown = bcm_gpio_set_shutdown; + dev->supplies[0].supply = "vbat"; + dev->supplies[1].supply = "vddio"; + err = devm_regulator_bulk_get(dev->dev, BCM_NUM_SUPPLIES, + dev->supplies); + if (err) + return err; + /* IRQ can be declared in ACPI table as Interrupt or GpioInt */ if (dev->irq <= 0) { struct gpio_desc *gpio; @@ -1314,6 +1418,8 @@ static void bcm_serdev_remove(struct serdev_device *serdev) #ifdef CONFIG_OF static const struct of_device_id bcm_bluetooth_of_match[] = { + { .compatible = "brcm,bcm20702a1" }, + { .compatible = "brcm,bcm4330-bt" }, { .compatible = "brcm,bcm43438-bt" }, { }, }; diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index fb97a3bf069b..5d97d77627c1 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -174,6 +174,10 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, struct hci_uart *hu = hci_get_drvdata(hdev); u8 alignment = hu->alignment ? hu->alignment : 1; + /* Check for error from previous call */ + if (IS_ERR(skb)) + skb = NULL; + while (count) { int i, len; diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 8eede1197cd2..069d1c8fde73 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -115,6 +115,8 @@ struct h5_vnd { int (*setup)(struct h5 *h5); void (*open)(struct h5 *h5); void (*close)(struct h5 *h5); + int (*suspend)(struct h5 *h5); + int (*resume)(struct h5 *h5); const struct acpi_gpio_mapping *acpi_gpio_map; }; @@ -841,6 +843,28 @@ static void h5_serdev_remove(struct serdev_device *serdev) hci_uart_unregister_device(&h5->serdev_hu); } +static int __maybe_unused h5_serdev_suspend(struct device *dev) +{ + struct h5 *h5 = dev_get_drvdata(dev); + int ret = 0; + + if (h5->vnd && h5->vnd->suspend) + ret = h5->vnd->suspend(h5); + + return ret; +} + +static int __maybe_unused h5_serdev_resume(struct device *dev) +{ + struct h5 *h5 = dev_get_drvdata(dev); + int ret = 0; + + if (h5->vnd && h5->vnd->resume) + ret = h5->vnd->resume(h5); + + return ret; +} + #ifdef CONFIG_BT_HCIUART_RTL static int h5_btrtl_setup(struct h5 *h5) { @@ -907,6 +931,56 @@ static void h5_btrtl_close(struct h5 *h5) gpiod_set_value_cansleep(h5->enable_gpio, 0); } +/* Suspend/resume support. On many devices the RTL BT device loses power during + * suspend/resume, causing it to lose its firmware and all state. So we simply + * turn it off on suspend and reprobe on resume. This mirrors how RTL devices + * are handled in the USB driver, where the USB_QUIRK_RESET_RESUME is used which + * also causes a reprobe on resume. + */ +static int h5_btrtl_suspend(struct h5 *h5) +{ + serdev_device_set_flow_control(h5->hu->serdev, false); + gpiod_set_value_cansleep(h5->device_wake_gpio, 0); + gpiod_set_value_cansleep(h5->enable_gpio, 0); + return 0; +} + +struct h5_btrtl_reprobe { + struct device *dev; + struct work_struct work; +}; + +static void h5_btrtl_reprobe_worker(struct work_struct *work) +{ + struct h5_btrtl_reprobe *reprobe = + container_of(work, struct h5_btrtl_reprobe, work); + int ret; + + ret = device_reprobe(reprobe->dev); + if (ret && ret != -EPROBE_DEFER) + dev_err(reprobe->dev, "Reprobe error %d\n", ret); + + put_device(reprobe->dev); + kfree(reprobe); + module_put(THIS_MODULE); +} + +static int h5_btrtl_resume(struct h5 *h5) +{ + struct h5_btrtl_reprobe *reprobe; + + reprobe = kzalloc(sizeof(*reprobe), GFP_KERNEL); + if (!reprobe) + return -ENOMEM; + + __module_get(THIS_MODULE); + + INIT_WORK(&reprobe->work, h5_btrtl_reprobe_worker); + reprobe->dev = get_device(&h5->hu->serdev->dev); + queue_work(system_long_wq, &reprobe->work); + return 0; +} + static const struct acpi_gpio_params btrtl_device_wake_gpios = { 0, 0, false }; static const struct acpi_gpio_params btrtl_enable_gpios = { 1, 0, false }; static const struct acpi_gpio_params btrtl_host_wake_gpios = { 2, 0, false }; @@ -921,6 +995,8 @@ static struct h5_vnd rtl_vnd = { .setup = h5_btrtl_setup, .open = h5_btrtl_open, .close = h5_btrtl_close, + .suspend = h5_btrtl_suspend, + .resume = h5_btrtl_resume, .acpi_gpio_map = acpi_btrtl_gpios, }; #endif @@ -935,12 +1011,17 @@ static const struct acpi_device_id h5_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, h5_acpi_match); #endif +static const struct dev_pm_ops h5_serdev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(h5_serdev_suspend, h5_serdev_resume) +}; + static struct serdev_device_driver h5_serdev_driver = { .probe = h5_serdev_probe, .remove = h5_serdev_remove, .driver = { .name = "hci_uart_h5", .acpi_match_table = ACPI_PTR(h5_acpi_match), + .pm = &h5_serdev_pm_ops, }, }; diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 46ace321bf60..f31410526c57 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -596,8 +596,8 @@ static int intel_setup(struct hci_uart *hu) * is in bootloader mode or if it already has operational firmware * loaded. */ - err = btintel_read_version(hdev, &ver); - if (err) + err = btintel_read_version(hdev, &ver); + if (err) return err; /* The hardware platform number has a fixed value of 0x37 and @@ -909,10 +909,8 @@ static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) set_bit(STATE_FIRMWARE_FAILED, &intel->flags); if (test_and_clear_bit(STATE_DOWNLOADING, &intel->flags) && - test_bit(STATE_FIRMWARE_LOADED, &intel->flags)) { - smp_mb__after_atomic(); + test_bit(STATE_FIRMWARE_LOADED, &intel->flags)) wake_up_bit(&intel->flags, STATE_DOWNLOADING); - } /* When switching to the operational firmware the device * sends a vendor specific event indicating that the bootup @@ -920,10 +918,8 @@ static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) */ } else if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 && skb->data[2] == 0x02) { - if (test_and_clear_bit(STATE_BOOTING, &intel->flags)) { - smp_mb__after_atomic(); + if (test_and_clear_bit(STATE_BOOTING, &intel->flags)) wake_up_bit(&intel->flags, STATE_BOOTING); - } } recv: return hci_recv_frame(hdev, skb); @@ -960,17 +956,13 @@ static int intel_recv_lpm(struct hci_dev *hdev, struct sk_buff *skb) break; case LPM_OP_SUSPEND_ACK: set_bit(STATE_SUSPENDED, &intel->flags); - if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) { - smp_mb__after_atomic(); + if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) wake_up_bit(&intel->flags, STATE_LPM_TRANSACTION); - } break; case LPM_OP_RESUME_ACK: clear_bit(STATE_SUSPENDED, &intel->flags); - if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) { - smp_mb__after_atomic(); + if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) wake_up_bit(&intel->flags, STATE_LPM_TRANSACTION); - } break; default: bt_dev_err(hdev, "Unknown LPM opcode (%02x)", lpm->opcode); diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index fbf7b4df23ab..9562e72c1ae5 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -207,11 +207,11 @@ void hci_uart_init_work(struct work_struct *work) err = hci_register_dev(hu->hdev); if (err < 0) { BT_ERR("Can't register HCI device"); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + hu->proto->close(hu); hdev = hu->hdev; hu->hdev = NULL; hci_free_dev(hdev); - clear_bit(HCI_UART_PROTO_READY, &hu->flags); - hu->proto->close(hu); return; } @@ -616,6 +616,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, static int hci_uart_register_dev(struct hci_uart *hu) { struct hci_dev *hdev; + int err; BT_DBG(""); @@ -659,11 +660,22 @@ static int hci_uart_register_dev(struct hci_uart *hu) else hdev->dev_type = HCI_PRIMARY; + /* Only call open() for the protocol after hdev is fully initialized as + * open() (or a timer/workqueue it starts) may attempt to reference it. + */ + err = hu->proto->open(hu); + if (err) { + hu->hdev = NULL; + hci_free_dev(hdev); + return err; + } + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) return 0; if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); + hu->proto->close(hu); hu->hdev = NULL; hci_free_dev(hdev); return -ENODEV; @@ -683,20 +695,14 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) if (!p) return -EPROTONOSUPPORT; - err = p->open(hu); - if (err) - return err; - hu->proto = p; - set_bit(HCI_UART_PROTO_READY, &hu->flags); err = hci_uart_register_dev(hu); if (err) { - clear_bit(HCI_UART_PROTO_READY, &hu->flags); - p->close(hu); return err; } + set_bit(HCI_UART_PROTO_READY, &hu->flags); return 0; } diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index f036c8f98ea3..237aea34b69f 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -59,7 +59,7 @@ #define IBS_WAKE_RETRANS_TIMEOUT_MS 100 #define IBS_TX_IDLE_TIMEOUT_MS 2000 -#define BAUDRATE_SETTLE_TIMEOUT_MS 300 +#define CMD_TRANS_TIMEOUT_MS 100 /* susclk rate */ #define SUSCLK_RATE_32KHZ 32768 @@ -770,16 +770,17 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); + spin_lock_irqsave(&qca->hci_ibs_lock, flags); + /* 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)) { skb_queue_tail(&qca->txq, skb); + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); return 0; } - spin_lock_irqsave(&qca->hci_ibs_lock, flags); - /* Act according to current state */ switch (qca->tx_ibs_state) { case HCI_IBS_TX_AWAKE: @@ -962,8 +963,8 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) { struct hci_uart *hu = hci_get_drvdata(hdev); struct qca_data *qca = hu->priv; - struct sk_buff *skb; struct qca_serdev *qcadev; + struct sk_buff *skb; u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 }; if (baudrate > QCA_BAUDRATE_3200000) @@ -977,13 +978,6 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) return -ENOMEM; } - /* Disabling hardware flow control is mandatory while - * sending change baudrate request to wcn3990 SoC. - */ - qcadev = serdev_device_get_drvdata(hu->serdev); - if (qcadev->btsoc_type == QCA_WCN3990) - hci_uart_set_flow_control(hu, true); - /* Assign commands to change baudrate and packet type. */ skb_put_data(skb, cmd, sizeof(cmd)); hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; @@ -991,16 +985,21 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) skb_queue_tail(&qca->txq, skb); hci_uart_tx_wakeup(hu); - /* wait 300ms to change new baudrate on controller side - * controller will come back after they receive this HCI command - * then host can communicate with new baudrate to controller - */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS)); - set_current_state(TASK_RUNNING); + qcadev = serdev_device_get_drvdata(hu->serdev); + + /* Wait for the baudrate change request to be sent */ + + while (!skb_queue_empty(&qca->txq)) + usleep_range(100, 200); + serdev_device_wait_until_sent(hu->serdev, + msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); + + /* Give the controller time to process the request */ if (qcadev->btsoc_type == QCA_WCN3990) - hci_uart_set_flow_control(hu, false); + msleep(10); + else + msleep(300); return 0; } @@ -1013,11 +1012,11 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) hci_uart_set_baudrate(hu, speed); } -static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) +static int qca_send_power_pulse(struct hci_uart *hu, bool on) { - struct hci_uart *hu = hci_get_drvdata(hdev); - struct qca_data *qca = hu->priv; - struct sk_buff *skb; + int ret; + int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); + u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE; /* These power pulses are single byte command which are sent * at required baudrate to wcn3990. On wcn3990, we have an external @@ -1029,24 +1028,25 @@ static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) * save power. Disabling hardware flow control is mandatory while * sending power pulses to SoC. */ - bt_dev_dbg(hdev, "sending power pulse %02x to SoC", cmd); - - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); - if (!skb) - return -ENOMEM; + bt_dev_dbg(hu->hdev, "sending power pulse %02x to controller", cmd); + serdev_device_write_flush(hu->serdev); hci_uart_set_flow_control(hu, true); + ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd)); + if (ret < 0) { + bt_dev_err(hu->hdev, "failed to send power pulse %02x", cmd); + return ret; + } - skb_put_u8(skb, cmd); - hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; - - skb_queue_tail(&qca->txq, skb); - hci_uart_tx_wakeup(hu); - - /* Wait for 100 uS for SoC to settle down */ - usleep_range(100, 200); + serdev_device_wait_until_sent(hu->serdev, timeout); hci_uart_set_flow_control(hu, false); + /* Give to controller time to boot/shutdown */ + if (on) + msleep(100); + else + msleep(10); + return 0; } @@ -1091,7 +1091,8 @@ static int qca_check_speeds(struct hci_uart *hu) static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) { unsigned int speed, qca_baudrate; - int ret; + struct qca_serdev *qcadev; + int ret = 0; if (speed_type == QCA_INIT_SPEED) { speed = qca_get_speed(hu, QCA_INIT_SPEED); @@ -1102,21 +1103,31 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) if (!speed) return 0; + /* Disable flow control for wcn3990 to deassert RTS while + * changing the baudrate of chip and host. + */ + qcadev = serdev_device_get_drvdata(hu->serdev); + if (qcadev->btsoc_type == QCA_WCN3990) + hci_uart_set_flow_control(hu, true); + qca_baudrate = qca_get_baudrate_value(speed); bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed); ret = qca_set_baudrate(hu->hdev, qca_baudrate); if (ret) - return ret; + goto error; host_set_baudrate(hu, speed); + +error: + if (qcadev->btsoc_type == QCA_WCN3990) + hci_uart_set_flow_control(hu, false); } - return 0; + return ret; } static int qca_wcn3990_init(struct hci_uart *hu) { - struct hci_dev *hdev = hu->hdev; struct qca_serdev *qcadev; int ret; @@ -1139,18 +1150,15 @@ static int qca_wcn3990_init(struct hci_uart *hu) /* Forcefully enable wcn3990 to enter in to boot mode. */ host_set_baudrate(hu, 2400); - ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE); + ret = qca_send_power_pulse(hu, false); if (ret) return ret; qca_set_speed(hu, QCA_INIT_SPEED); - ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWERON_PULSE); + ret = qca_send_power_pulse(hu, true); if (ret) return ret; - /* Wait for 100 ms for SoC to boot */ - msleep(100); - /* Now the device is in ready state to communicate with host. * To sync host with device we need to reopen port. * Without this, we will have RTS and CTS synchronization @@ -1193,6 +1201,7 @@ static int qca_setup(struct hci_uart *hu) * setup for every hci up. */ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); hu->hdev->shutdown = qca_power_off; ret = qca_wcn3990_init(hu); if (ret) @@ -1241,7 +1250,10 @@ static int qca_setup(struct hci_uart *hu) } /* Setup bdaddr */ - hu->hdev->set_bdaddr = qca_set_bdaddr_rome; + if (qcadev->btsoc_type == QCA_WCN3990) + hu->hdev->set_bdaddr = qca_set_bdaddr; + else + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; return ret; } @@ -1274,13 +1286,20 @@ static const struct qca_vreg_data qca_soc_data = { static void qca_power_shutdown(struct hci_uart *hu) { - struct serdev_device *serdev = hu->serdev; - unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE; + struct qca_data *qca = hu->priv; + unsigned long flags; + + /* From this point we go into power off state. But serial port is + * still open, stop queueing the IBS data and flush all the buffered + * data in skb's. + */ + spin_lock_irqsave(&qca->hci_ibs_lock, flags); + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + qca_flush(hu); + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); host_set_baudrate(hu, 2400); - hci_uart_set_flow_control(hu, true); - serdev_device_write_buf(serdev, &cmd, sizeof(cmd)); - hci_uart_set_flow_control(hu, false); + qca_send_power_pulse(hu, false); qca_power_setup(hu, false); } diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index c445aa9ac511..490abba94363 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -333,9 +333,6 @@ int hci_uart_register_device(struct hci_uart *hu, if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); - if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) - set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); - if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) hdev->dev_type = HCI_AMP; else |