summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZijun Hu <zijuhu@codeaurora.org>2020-05-29 21:56:57 +0800
committerMarcel Holtmann <marcel@holtmann.org>2020-05-29 16:04:29 +0200
commit7e7bbddd029b644f00f0ffbfbc485ed71977d0d5 (patch)
treeece40eca4c84023d4c817c5898d9953844708b8a
parente6da0edc24eecef2f6964d92fa9044e1821deace (diff)
downloadlinux-7e7bbddd029b644f00f0ffbfbc485ed71977d0d5.tar.bz2
Bluetooth: hci_qca: Fix qca6390 enable failure after warm reboot
Warm reboot can not reset controller qca6390 due to lack of controllable power supply, so causes firmware download failure during enable. Fixed by sending VSC EDL_SOC_RESET to reset qca6390 within added device shutdown implementation. Signed-off-by: Zijun Hu <zijuhu@codeaurora.org> Tested-by: Zijun Hu <zijuhu@codeaurora.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--drivers/bluetooth/hci_qca.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index adcbe00a2275..aa957d749d6f 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1975,6 +1975,38 @@ static void qca_serdev_remove(struct serdev_device *serdev)
hci_uart_unregister_device(&qcadev->serdev_hu);
}
+static void qca_serdev_shutdown(struct device *dev)
+{
+ int ret;
+ int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
+ struct serdev_device *serdev = to_serdev_device(dev);
+ struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
+ const u8 ibs_wake_cmd[] = { 0xFD };
+ const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 };
+
+ if (qcadev->btsoc_type == QCA_QCA6390) {
+ serdev_device_write_flush(serdev);
+ ret = serdev_device_write_buf(serdev, ibs_wake_cmd,
+ sizeof(ibs_wake_cmd));
+ if (ret < 0) {
+ BT_ERR("QCA send IBS_WAKE_IND error: %d", ret);
+ return;
+ }
+ serdev_device_wait_until_sent(serdev, timeout);
+ usleep_range(8000, 10000);
+
+ serdev_device_write_flush(serdev);
+ ret = serdev_device_write_buf(serdev, edl_reset_soc_cmd,
+ sizeof(edl_reset_soc_cmd));
+ if (ret < 0) {
+ BT_ERR("QCA send EDL_RESET_REQ error: %d", ret);
+ return;
+ }
+ serdev_device_wait_until_sent(serdev, timeout);
+ usleep_range(8000, 10000);
+ }
+}
+
static int __maybe_unused qca_suspend(struct device *dev)
{
struct serdev_device *serdev = to_serdev_device(dev);
@@ -2102,6 +2134,7 @@ static struct serdev_device_driver qca_serdev_driver = {
.name = "hci_uart_qca",
.of_match_table = of_match_ptr(qca_bluetooth_of_match),
.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
+ .shutdown = qca_serdev_shutdown,
.pm = &qca_pm_ops,
},
};