diff options
Diffstat (limited to 'drivers/bluetooth/btmrvl_sdio.c')
| -rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 149 |
1 files changed, 87 insertions, 62 deletions
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index eb794f08b238..93932a0d8625 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1,21 +1,8 @@ -/** +// SPDX-License-Identifier: GPL-2.0-only +/* * Marvell BT-over-SDIO driver: SDIO interface related functions. * * Copyright (C) 2009, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. **/ #include <linux/firmware.h> @@ -53,7 +40,7 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = { {"EXTLAST", NULL, 0, 0xFE}, }; -static const struct of_device_id btmrvl_sdio_of_match_table[] = { +static const struct of_device_id btmrvl_sdio_of_match_table[] __maybe_unused = { { .compatible = "marvell,sd8897-bt" }, { .compatible = "marvell,sd8997-bt" }, { } @@ -62,13 +49,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", __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 +75,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"); + dev_info(dev, "sdio device tree data not available\n"); return -1; } @@ -99,18 +87,22 @@ static int btmrvl_sdio_probe_of(struct device *dev, if (cfg && card->plt_of_node) { cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0); if (!cfg->irq_bt) { - dev_err(dev, "fail to parse irq_bt from device tree"); + dev_err(dev, "fail to parse irq_bt from device tree\n"); cfg->irq_bt = -1; } else { ret = devm_request_irq(dev, cfg->irq_bt, btmrvl_wake_irq_bt, - 0, "bt_wake", card); + IRQF_NO_AUTOEN, "bt_wake", card); if (ret) { dev_err(dev, "Failed to request irq_bt %d (%d)\n", cfg->irq_bt, ret); } - disable_irq(cfg->irq_bt); + + /* Configure wakeup (enabled by default) */ + ret = devm_device_init_wakeup(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to init wakeup\n"); } } @@ -211,7 +203,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { .fw_dump_end = 0xea, }; -static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = { +static const struct btmrvl_sdio_card_reg btmrvl_reg_89xx = { .cfg = 0x00, .host_int_mask = 0x08, .host_intstatus = 0x0c, @@ -228,7 +220,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = { .io_port_2 = 0xe6, .int_read_to_clear = true, .host_int_rsr = 0x04, - .card_misc_cfg = 0xD8, + .card_misc_cfg = 0xd8, .fw_dump_ctrl = 0xf0, .fw_dump_start = 0xf1, .fw_dump_end = 0xf8, @@ -279,10 +271,28 @@ 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/sdsd8977_combo_v2.bin", + .reg = &btmrvl_reg_89xx, + .support_pscan_win_report = true, + .sd_blksz_fw_dl = 256, + .supports_fw_dump = true, +}; + +static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = { + .helper = NULL, + .firmware = "mrvl/sd8987_uapsta.bin", + .reg = &btmrvl_reg_89xx, + .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", - .reg = &btmrvl_reg_8997, + .firmware = "mrvl/sdsd8997_combo_v4.bin", + .reg = &btmrvl_reg_89xx, .support_pscan_win_report = true, .sd_blksz_fw_dl = 256, .supports_fw_dump = true, @@ -290,25 +300,31 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = { static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8688 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8688 }, /* Marvell SD8787 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8787 }, /* Marvell SD8787 Bluetooth AMP device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_BT_AMP), .driver_data = (unsigned long)&btmrvl_sdio_sd8787 }, /* Marvell SD8797 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8797 }, /* Marvell SD8887 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8887 }, /* Marvell SD8897 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8897 }, + /* Marvell SD8977 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8977_BT), + .driver_data = (unsigned long)&btmrvl_sdio_sd8977 }, + /* Marvell SD8987 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8987_BT), + .driver_data = (unsigned long)&btmrvl_sdio_sd8987 }, /* Marvell SD8997 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8997 }, { } /* Terminating entry */ @@ -689,7 +705,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) int ret, num_blocks, blksz; struct sk_buff *skb = NULL; u32 type; - u8 *payload = NULL; + u8 *payload; struct hci_dev *hdev = priv->btmrvl_dev.hcidev; struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; @@ -718,7 +734,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) } /* Allocate buffer */ - skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC); + skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_KERNEL); if (!skb) { BT_ERR("No free skb"); ret = -ENOMEM; @@ -920,7 +936,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) { struct sdio_func *func; u8 reg; - int ret = 0; + int ret; if (!card || !card->func) { BT_ERR("Error: card or function is NULL!"); @@ -1311,15 +1327,21 @@ rdwr_status btmrvl_sdio_rdwr_firmware(struct btmrvl_private *priv, } /* This function dump sdio register and memory data */ -static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv) +static void btmrvl_sdio_coredump(struct device *dev) { - struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + struct sdio_func *func = dev_to_sdio_func(dev); + struct btmrvl_sdio_card *card; + struct btmrvl_private *priv; int ret = 0; unsigned int reg, reg_start, reg_end; enum rdwr_status stat; u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr; u8 dump_num = 0, idx, i, read_reg, doneflag = 0; u32 memory_size, fw_dump_len = 0; + int size = 0; + + card = sdio_get_drvdata(func); + priv = card->priv; /* dump sdio register first */ btmrvl_sdio_dump_regs(priv); @@ -1428,9 +1450,7 @@ static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv) BT_ERR("Allocated buffer not enough"); } - if (stat != RDWR_STATUS_DONE) { - continue; - } else { + if (stat == RDWR_STATUS_DONE) { BT_INFO("%s done: size=0x%tx", entry->mem_name, dbg_ptr - entry->mem_ptr); @@ -1447,7 +1467,7 @@ done: if (fw_dump_len == 0) return; - fw_dump_data = vzalloc(fw_dump_len+1); + fw_dump_data = vzalloc(fw_dump_len + 1); if (!fw_dump_data) { BT_ERR("Vzalloc fw_dump_data fail!"); return; @@ -1455,26 +1475,25 @@ done: fw_dump_ptr = fw_dump_data; /* Dump all the memory data into single file, a userspace script will - be used to split all the memory data to multiple files*/ + * be used to split all the memory data to multiple files + */ BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump start"); for (idx = 0; idx < dump_num; idx++) { struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; if (entry->mem_ptr) { - strcpy(fw_dump_ptr, "========Start dump "); - fw_dump_ptr += strlen("========Start dump "); + size += scnprintf(fw_dump_ptr + size, + fw_dump_len + 1 - size, + "========Start dump %s========\n", + entry->mem_name); - strcpy(fw_dump_ptr, entry->mem_name); - fw_dump_ptr += strlen(entry->mem_name); + memcpy(fw_dump_ptr + size, entry->mem_ptr, + entry->mem_size); + size += entry->mem_size; - strcpy(fw_dump_ptr, "========\n"); - fw_dump_ptr += strlen("========\n"); - - memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size); - fw_dump_ptr += entry->mem_size; - - strcpy(fw_dump_ptr, "\n========End dump========\n"); - fw_dump_ptr += strlen("\n========End dump========\n"); + size += scnprintf(fw_dump_ptr + size, + fw_dump_len + 1 - size, + "\n========End dump========\n"); vfree(mem_type_mapping_tbl[idx].mem_ptr); mem_type_mapping_tbl[idx].mem_ptr = NULL; @@ -1482,7 +1501,8 @@ done: } /* fw_dump_data will be free in device coredump release function - after 5 min*/ + * after 5 min + */ dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL); BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end"); } @@ -1545,7 +1565,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, priv->hw_host_to_card = btmrvl_sdio_host_to_card; priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; priv->hw_process_int_status = btmrvl_sdio_process_int_status; - priv->firmware_dump = btmrvl_sdio_dump_firmware; if (btmrvl_register_hdev(priv)) { BT_ERR("Register hdev failed!"); @@ -1577,6 +1596,7 @@ static void btmrvl_sdio_remove(struct sdio_func *func) MODULE_SHUTDOWN_REQ); btmrvl_sdio_disable_host_int(card); } + BT_DBG("unregister dev"); card->priv->surprise_removed = true; btmrvl_sdio_unregister_dev(card); @@ -1613,7 +1633,8 @@ static int btmrvl_sdio_suspend(struct device *dev) } /* Enable platform specific wakeup interrupt */ - if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) { + if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0 && + device_may_wakeup(dev)) { card->plt_wake_cfg->wake_by_bt = false; enable_irq(card->plt_wake_cfg->irq_bt); enable_irq_wake(card->plt_wake_cfg->irq_bt); @@ -1630,7 +1651,8 @@ static int btmrvl_sdio_suspend(struct device *dev) BT_ERR("HS not activated, suspend failed!"); /* Disable platform specific wakeup interrupt */ if (card->plt_wake_cfg && - card->plt_wake_cfg->irq_bt >= 0) { + card->plt_wake_cfg->irq_bt >= 0 && + device_may_wakeup(dev)) { disable_irq_wake(card->plt_wake_cfg->irq_bt); disable_irq(card->plt_wake_cfg->irq_bt); } @@ -1690,7 +1712,8 @@ static int btmrvl_sdio_resume(struct device *dev) hci_resume_dev(hcidev); /* Disable platform specific wakeup interrupt */ - if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) { + if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0 && + device_may_wakeup(dev)) { disable_irq_wake(card->plt_wake_cfg->irq_bt); disable_irq(card->plt_wake_cfg->irq_bt); if (card->plt_wake_cfg->wake_by_bt) @@ -1714,7 +1737,7 @@ static struct sdio_driver bt_mrvl_sdio = { .probe = btmrvl_sdio_probe, .remove = btmrvl_sdio_remove, .drv = { - .owner = THIS_MODULE, + .coredump = btmrvl_sdio_coredump, .pm = &btmrvl_sdio_pm_ops, } }; @@ -1753,4 +1776,6 @@ 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/sd8997_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sdsd8977_combo_v2.bin"); +MODULE_FIRMWARE("mrvl/sd8987_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sdsd8997_combo_v4.bin"); |
