summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-10-17 13:59:11 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2018-10-17 13:59:10 -0700
commit85edf1b9737dce14f19084437bb389709d1aa069 (patch)
tree81e035161085d69e526cfec07ec4b984de719b0e /drivers
parent2a72f7f7fedda6f58a71d9e01d70b4a57a3038fd (diff)
parent616ea9d08bebd6f0c581806d051c5562f1d50565 (diff)
Merge "cnss2: Add support for USB transport"
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/cnss2/Makefile1
-rw-r--r--drivers/net/wireless/cnss2/bus.c40
-rw-r--r--drivers/net/wireless/cnss2/bus.h9
-rw-r--r--drivers/net/wireless/cnss2/main.c53
-rw-r--r--drivers/net/wireless/cnss2/main.h4
-rw-r--r--drivers/net/wireless/cnss2/qmi.c19
-rw-r--r--drivers/net/wireless/cnss2/qmi.h4
-rw-r--r--drivers/net/wireless/cnss2/usb.c361
-rw-r--r--drivers/net/wireless/cnss2/usb.h66
9 files changed, 553 insertions, 4 deletions
diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile
index 318076f23213..a4b177e7a981 100644
--- a/drivers/net/wireless/cnss2/Makefile
+++ b/drivers/net/wireless/cnss2/Makefile
@@ -4,6 +4,7 @@ cnss2-y := main.o
cnss2-y += bus.o
cnss2-y += debug.o
cnss2-y += pci.o
+cnss2-y += usb.o
cnss2-y += power.o
cnss2-y += qmi.o
cnss2-y += wlan_firmware_service_v01.o
diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c
index c0810df81bfc..17da90259084 100644
--- a/drivers/net/wireless/cnss2/bus.c
+++ b/drivers/net/wireless/cnss2/bus.c
@@ -13,6 +13,7 @@
#include "bus.h"
#include "debug.h"
#include "pci.h"
+#include "usb.h"
enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
{
@@ -36,12 +37,33 @@ enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id)
case QCA6290_DEVICE_ID:
case QCN7605_DEVICE_ID:
return CNSS_BUS_PCI;
+ case QCN7605_COMPOSITE_DEVICE_ID:
+ case QCN7605_STANDALONE_DEVICE_ID:
+ return CNSS_BUS_USB;
default:
cnss_pr_err("Unknown device_id: 0x%lx\n", device_id);
return CNSS_BUS_NONE;
}
}
+bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv)
+{
+ if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
+ return false;
+ else
+ return true;
+}
+
+bool cnss_bus_dev_cal_rep_valid(struct cnss_plat_data *plat_priv)
+{
+ bool ret = false;
+
+ if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
+ ret = true;
+
+ return ret;
+}
+
void *cnss_bus_dev_to_bus_priv(struct device *dev)
{
if (!dev)
@@ -69,6 +91,8 @@ struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
switch (cnss_get_dev_bus_type(dev)) {
case CNSS_BUS_PCI:
return cnss_pci_priv_to_plat_priv(bus_priv);
+ case CNSS_BUS_USB:
+ return cnss_usb_priv_to_plat_priv(bus_priv);
default:
return NULL;
}
@@ -82,6 +106,8 @@ int cnss_bus_init(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_init(plat_priv);
+ case CNSS_BUS_USB:
+ return cnss_usb_init(plat_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -97,6 +123,8 @@ void cnss_bus_deinit(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
cnss_pci_deinit(plat_priv);
+ case CNSS_BUS_USB:
+ cnss_usb_deinit(plat_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -212,6 +240,8 @@ int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_call_driver_probe(plat_priv->bus_priv);
+ case CNSS_BUS_USB:
+ return cnss_usb_call_driver_probe(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -227,6 +257,8 @@ int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_call_driver_remove(plat_priv->bus_priv);
+ case CNSS_BUS_USB:
+ return cnss_usb_call_driver_remove(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -242,6 +274,8 @@ int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_dev_powerup(plat_priv->bus_priv);
+ case CNSS_BUS_USB:
+ return 0;
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -257,6 +291,8 @@ int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_dev_shutdown(plat_priv->bus_priv);
+ case CNSS_BUS_USB:
+ return 0;
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -302,6 +338,8 @@ int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
+ case CNSS_BUS_USB:
+ return cnss_usb_register_driver_hdlr(plat_priv->bus_priv, data);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -317,6 +355,8 @@ int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
+ case CNSS_BUS_USB:
+ return cnss_usb_unregister_driver_hdlr(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h
index bd32a94e5146..415f1ae6cfed 100644
--- a/drivers/net/wireless/cnss2/bus.h
+++ b/drivers/net/wireless/cnss2/bus.h
@@ -27,6 +27,13 @@
#define QCN7605_VENDOR_ID 0x17CB
#define QCN7605_DEVICE_ID 0x1102
+#define QCN7605_USB_VENDOR_ID 0x05C6
+#define QCN7605_COMPOSITE_DEVICE_ID QCN7605_COMPOSITE_PRODUCT_ID
+#define QCN7605_STANDALONE_DEVICE_ID QCN7605_STANDALONE_PRODUCT_ID
+
+#define QCN7605_STANDALONE_PRODUCT_ID 0x9900
+#define QCN7605_COMPOSITE_PRODUCT_ID 0x9901
+
enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev);
enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id);
void *cnss_bus_dev_to_bus_priv(struct device *dev);
@@ -50,4 +57,6 @@ int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv);
int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
int modem_current_status);
int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv);
+bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv);
+bool cnss_bus_dev_cal_rep_valid(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_BUS_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index ac9d8e7d08ad..9c1b29fc6e27 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -559,6 +559,15 @@ out:
return ret;
}
+static int cnss_cal_update_hdlr(struct cnss_plat_data *plat_priv)
+{
+ /* QCN7605 store the cal data sent by FW to calDB memory area
+ * get out of this after complete data is uploaded. FW is expected
+ * to send cal done
+ */
+ return 0;
+}
+
static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
{
switch (type) {
@@ -576,6 +585,10 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
return "COLD_BOOT_CAL_START";
case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
return "COLD_BOOT_CAL_DONE";
+ case CNSS_DRIVER_EVENT_CAL_UPDATE:
+ return "COLD_BOOT_CAL_DATA_UPDATE";
+ case CNSS_DRIVER_EVENT_CAL_DOWNLOAD:
+ return "COLD_BOOT_CAL_DATA_DOWNLOAD";
case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
return "REGISTER_DRIVER";
case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
@@ -1127,6 +1140,30 @@ int cnss_force_fw_assert(struct device *dev)
}
EXPORT_SYMBOL(cnss_force_fw_assert);
+static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
+{
+ int ret;
+
+ ret = cnss_wlfw_server_arrive(plat_priv);
+ if (ret)
+ goto out;
+
+ if (!cnss_bus_req_mem_ind_valid(plat_priv)) {
+ ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
+ if (ret)
+ goto out;
+
+ ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
+ if (ret)
+ goto out;
+ /*cnss driver sends meta data report and waits for FW_READY*/
+ if (cnss_bus_dev_cal_rep_valid(plat_priv))
+ ret = cnss_wlfw_cal_report_send_sync(plat_priv);
+ }
+out:
+ return ret;
+}
+
static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -1146,9 +1183,9 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
if (plat_priv->device_id == QCN7605_DEVICE_ID)
goto skip_shutdown;
cnss_bus_dev_shutdown(plat_priv);
+
skip_shutdown:
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
-
return 0;
}
@@ -1194,7 +1231,7 @@ static void cnss_driver_event_work(struct work_struct *work)
switch (event->type) {
case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
- ret = cnss_wlfw_server_arrive(plat_priv);
+ ret = cnss_wlfw_server_arrive_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_SERVER_EXIT:
ret = cnss_wlfw_server_exit(plat_priv);
@@ -1214,6 +1251,9 @@ static void cnss_driver_event_work(struct work_struct *work)
case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
break;
+ case CNSS_DRIVER_EVENT_CAL_UPDATE:
+ ret = cnss_cal_update_hdlr(plat_priv);
+ break;
case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
break;
@@ -1278,6 +1318,8 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv)
subsys_info->subsys_desc.name = "QCA6290";
break;
case QCN7605_DEVICE_ID:
+ case QCN7605_STANDALONE_DEVICE_ID:
+ case QCN7605_COMPOSITE_DEVICE_ID:
subsys_info->subsys_desc.name = "QCN7605";
break;
default:
@@ -1498,6 +1540,10 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
case QCN7605_DEVICE_ID:
ret = cnss_register_ramdump_v2(plat_priv);
break;
+ case QCN7605_COMPOSITE_DEVICE_ID:
+ case QCN7605_STANDALONE_DEVICE_ID:
+ break;
+
default:
cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
ret = -ENODEV;
@@ -1516,6 +1562,9 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
case QCA6290_DEVICE_ID:
cnss_unregister_ramdump_v2(plat_priv);
break;
+ case QCN7605_COMPOSITE_DEVICE_ID:
+ case QCN7605_STANDALONE_DEVICE_ID:
+ break;
default:
cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
break;
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index 9dc64e016d82..ec67d31ea945 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -33,6 +33,7 @@
enum cnss_dev_bus_type {
CNSS_BUS_NONE = -1,
CNSS_BUS_PCI,
+ CNSS_BUS_USB,
};
struct cnss_vreg_info {
@@ -124,6 +125,8 @@ enum cnss_driver_event_type {
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
CNSS_DRIVER_EVENT_POWER_UP,
CNSS_DRIVER_EVENT_POWER_DOWN,
+ CNSS_DRIVER_EVENT_CAL_UPDATE,
+ CNSS_DRIVER_EVENT_CAL_DOWNLOAD,
CNSS_DRIVER_EVENT_MAX,
};
@@ -245,4 +248,5 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
bool *cnss_get_qmi_bypass(void);
+bool is_qcn7605_device(u16 device_id);
#endif /* _CNSS_MAIN_H */
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index 669816c84e37..fb2841360265 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -238,6 +238,10 @@ static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
req.fw_init_done_enable = 1;
req.pin_connect_result_enable_valid = 1;
req.pin_connect_result_enable = 1;
+ req.initiate_cal_download_enable_valid = 1;
+ req.initiate_cal_download_enable = 1;
+ req.initiate_cal_update_enable_valid = 1;
+ req.initiate_cal_update_enable = 1;
req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
@@ -269,6 +273,13 @@ out:
return ret;
}
+static int cnss_qmi_initiate_cal_update_ind_hdlr(
+ struct cnss_plat_data *plat_priv,
+ void *msg, unsigned int msg_len)
+{
+ return 0;
+}
+
static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
void *msg, unsigned int msg_len)
{
@@ -941,6 +952,11 @@ out:
return ret;
}
+int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv)
+{
+ return 0;
+}
+
static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
unsigned int msg_len, void *ind_cb_priv)
@@ -977,6 +993,9 @@ static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
case QMI_WLFW_PIN_CONNECT_RESULT_IND_V01:
cnss_qmi_pin_result_ind_hdlr(plat_priv, msg, msg_len);
break;
+ case QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01:
+ cnss_qmi_initiate_cal_update_ind_hdlr(plat_priv, msg, msg_len);
+ break;
default:
cnss_pr_err("Invalid QMI WLFW indication, msg_id: 0x%x\n",
msg_id);
diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h
index 70d8d404c48e..c6a1e6733505 100644
--- a/drivers/net/wireless/cnss2/qmi.h
+++ b/drivers/net/wireless/cnss2/qmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,5 +37,5 @@ int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
u32 data_len, u8 *data);
int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
u8 fw_log_mode);
-
+int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_QMI_H */
diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c
new file mode 100644
index 000000000000..6cf5aaea1b37
--- /dev/null
+++ b/drivers/net/wireless/cnss2/usb.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "main.h"
+#include "bus.h"
+#include "debug.h"
+#include "usb.h"
+
+int cnss_usb_dev_powerup(struct cnss_usb_data *usb_priv)
+{
+ int ret = 0;
+
+ if (!usb_priv) {
+ cnss_pr_err("usb_priv is NULL\n");
+ return -ENODEV;
+ }
+ return ret;
+}
+
+int cnss_usb_wlan_register_driver(struct cnss_usb_wlan_driver *driver_ops)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct cnss_usb_data *usb_priv;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ usb_priv = plat_priv->bus_priv;
+ if (!usb_priv) {
+ cnss_pr_err("usb_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ if (usb_priv->driver_ops) {
+ cnss_pr_err("Driver has already registered\n");
+ return -EEXIST;
+ }
+
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+ driver_ops);
+ return ret;
+}
+EXPORT_SYMBOL(cnss_usb_wlan_register_driver);
+
+void cnss_usb_wlan_unregister_driver(struct cnss_usb_wlan_driver *driver_ops)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return;
+ }
+
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(cnss_usb_wlan_unregister_driver);
+
+int cnss_usb_register_driver_hdlr(struct cnss_usb_data *usb_priv,
+ void *data)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = usb_priv->plat_priv;
+
+ set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ usb_priv->driver_ops = data;
+
+ ret = cnss_bus_call_driver_probe(plat_priv);
+
+ return ret;
+}
+
+int cnss_usb_unregister_driver_hdlr(struct cnss_usb_data *usb_priv)
+{
+ struct cnss_plat_data *plat_priv = usb_priv->plat_priv;
+
+ set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+ cnss_usb_dev_shutdown(usb_priv);
+ usb_priv->driver_ops = NULL;
+
+ return 0;
+}
+
+int cnss_usb_dev_shutdown(struct cnss_usb_data *usb_priv)
+{
+ int ret = 0;
+
+ if (!usb_priv) {
+ cnss_pr_err("usb_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (usb_priv->device_id) {
+ case QCN7605_COMPOSITE_DEVICE_ID:
+ case QCN7605_STANDALONE_DEVICE_ID:
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ usb_priv->device_id);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+int cnss_usb_call_driver_probe(struct cnss_usb_data *usb_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = usb_priv->plat_priv;
+
+ if (!usb_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ ret = usb_priv->driver_ops->reinit(usb_priv->usb_intf,
+ usb_priv->usb_device_id);
+ if (ret) {
+ cnss_pr_err("Failed to reinit host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+ ret = usb_priv->driver_ops->probe(usb_priv->usb_intf,
+ usb_priv->usb_device_id);
+ if (ret) {
+ cnss_pr_err("Failed to probe host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+int cnss_usb_call_driver_remove(struct cnss_usb_data *usb_priv)
+{
+ struct cnss_plat_data *plat_priv = usb_priv->plat_priv;
+
+ if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+ test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Skip driver remove\n");
+ return 0;
+ }
+
+ if (!usb_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ return -EINVAL;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ usb_priv->driver_ops->shutdown(usb_priv->usb_intf);
+ } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ usb_priv->driver_ops->remove(usb_priv->usb_intf);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+}
+
+static struct usb_driver cnss_usb_driver;
+#define QCN7605_WLAN_INTERFACE_NUM 0x0000
+
+static int cnss_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ret = 0;
+ struct cnss_usb_data *usb_priv;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct usb_device *usb_dev;
+ unsigned short bcd_device;
+
+ cnss_pr_dbg("USB probe, vendor ID: 0x%x, product ID: 0x%x\n",
+ id->idVendor, id->idProduct);
+
+ usb_dev = interface_to_usbdev(interface);
+ usb_priv = devm_kzalloc(&usb_dev->dev, sizeof(*usb_priv),
+ GFP_KERNEL);
+ if (!usb_priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (interface->cur_altsetting->desc.bInterfaceNumber ==
+ QCN7605_WLAN_INTERFACE_NUM) {
+ if (usb_driver_claim_interface(&cnss_usb_driver,
+ interface,
+ NULL)) {
+ ret = -ENODEV;
+ goto reset_priv;
+ }
+ }
+ bcd_device = le16_to_cpu(usb_dev->descriptor.bcdDevice);
+ usb_priv->plat_priv = plat_priv;
+ usb_priv->usb_intf = interface;
+ usb_priv->usb_device_id = id;
+ usb_priv->device_id = id->idProduct;
+ usb_priv->target_version = bcd_device;
+ cnss_set_usb_priv(interface, usb_priv);
+ plat_priv->device_id = usb_priv->device_id;
+ plat_priv->bus_priv = usb_priv;
+
+ /*increment the ref count of usb dev structure*/
+ usb_get_dev(usb_dev);
+
+ ret = cnss_register_subsys(plat_priv);
+ if (ret)
+ goto reset_ctx;
+
+ ret = cnss_register_ramdump(plat_priv);
+ if (ret)
+ goto unregister_subsys;
+
+ switch (usb_priv->device_id) {
+ case QCN7605_COMPOSITE_DEVICE_ID:
+ case QCN7605_STANDALONE_DEVICE_ID:
+ break;
+ default:
+ cnss_pr_err("Unknown USB device found: 0x%x\n",
+ usb_priv->device_id);
+ ret = -ENODEV;
+ goto unregister_ramdump;
+ }
+
+ return 0;
+
+unregister_ramdump:
+ cnss_unregister_ramdump(plat_priv);
+unregister_subsys:
+ cnss_unregister_subsys(plat_priv);
+reset_ctx:
+ plat_priv->bus_priv = NULL;
+reset_priv:
+ devm_kfree(&usb_dev->dev, usb_priv);
+out:
+ return ret;
+}
+
+static void cnss_usb_remove(struct usb_interface *interface)
+{
+ struct usb_device *usb_dev;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct cnss_usb_data *usb_priv = plat_priv->bus_priv;
+
+ usb_priv->plat_priv = NULL;
+ plat_priv->bus_priv = NULL;
+ usb_dev = interface_to_usbdev(interface);
+ usb_put_dev(usb_dev);
+ devm_kfree(&usb_dev->dev, usb_priv);
+}
+
+static int cnss_usb_suspend(struct usb_interface *interface, pm_message_t state)
+{
+ int ret = 0;
+ struct cnss_usb_data *usb_priv;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+
+ usb_priv = plat_priv->bus_priv;
+ if (!usb_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = usb_priv->driver_ops->suspend(usb_priv->usb_intf,
+ state);
+out:
+ return ret;
+}
+
+static int cnss_usb_resume(struct usb_interface *interface)
+{
+ int ret = 0;
+ struct cnss_usb_data *usb_priv;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+
+ usb_priv = plat_priv->bus_priv;
+ if (!usb_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = usb_priv->driver_ops->resume(usb_priv->usb_intf);
+
+out:
+ return ret;
+}
+
+static int cnss_usb_reset_resume(struct usb_interface *interface)
+{
+ return 0;
+}
+
+static struct usb_device_id cnss_usb_id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(QCN7605_USB_VENDOR_ID,
+ QCN7605_COMPOSITE_PRODUCT_ID,
+ QCN7605_WLAN_INTERFACE_NUM,
+ 0xFF, 0xFF) },
+ { USB_DEVICE_AND_INTERFACE_INFO(QCN7605_USB_VENDOR_ID,
+ QCN7605_STANDALONE_PRODUCT_ID,
+ QCN7605_WLAN_INTERFACE_NUM,
+ 0xFF, 0xFF) },
+ {} /* Terminating entry */
+};
+
+static struct usb_driver cnss_usb_driver = {
+ .name = "cnss_usb",
+ .id_table = cnss_usb_id_table,
+ .probe = cnss_usb_probe,
+ .disconnect = cnss_usb_remove,
+ .suspend = cnss_usb_suspend,
+ .resume = cnss_usb_resume,
+ .reset_resume = cnss_usb_reset_resume,
+ .supports_autosuspend = true,
+};
+
+int cnss_usb_init(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ ret = usb_register(&cnss_usb_driver);
+ if (ret) {
+ cnss_pr_err("Failed to register to Linux USB framework, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+void cnss_usb_deinit(struct cnss_plat_data *plat_priv)
+{
+ usb_deregister(&cnss_usb_driver);
+}
diff --git a/drivers/net/wireless/cnss2/usb.h b/drivers/net/wireless/cnss2/usb.h
new file mode 100644
index 000000000000..b285dc27daa9
--- /dev/null
+++ b/drivers/net/wireless/cnss2/usb.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_USB_H
+#define _CNSS_USB_H
+
+#include <linux/usb.h>
+
+#include "main.h"
+
+struct cnss_usb_data {
+ struct usb_interface *usb_intf;
+ struct cnss_plat_data *plat_priv;
+ const struct usb_device_id *usb_device_id;
+ u16 device_id; /*USB PID*/
+ u16 target_version; /* [QCN7605] - from bcdDevice*/
+ struct cnss_usb_wlan_driver *driver_ops;
+};
+
+static inline void cnss_set_usb_priv(struct usb_interface *usb_intf, void *data)
+{
+ usb_set_intfdata(usb_intf, data);
+}
+
+static inline struct cnss_usb_data *cnss_get_usb_priv(struct usb_interface
+ *usb_intf)
+{
+ return usb_get_intfdata(usb_intf);
+}
+
+static inline struct cnss_plat_data *cnss_usb_priv_to_plat_priv(void *bus_priv)
+{
+ struct cnss_usb_data *usb_priv = bus_priv;
+
+ return usb_priv->plat_priv;
+}
+
+int cnss_usb_init(struct cnss_plat_data *plat_priv);
+void cnss_usb_deinit(struct cnss_plat_data *plat_priv);
+void cnss_usb_collect_dump_info(struct cnss_usb_data *usb_priv, bool in_panic);
+void cnss_usb_clear_dump_info(struct cnss_usb_data *usb_priv);
+int cnss_usb_force_fw_assert_hdlr(struct cnss_usb_data *usb_priv);
+void cnss_usb_fw_boot_timeout_hdlr(struct cnss_usb_data *usb_priv);
+int cnss_usb_call_driver_probe(struct cnss_usb_data *usb_priv);
+int cnss_usb_call_driver_remove(struct cnss_usb_data *usb_priv);
+int cnss_usb_dev_powerup(struct cnss_usb_data *usb_priv);
+int cnss_usb_dev_shutdown(struct cnss_usb_data *usb_priv);
+int cnss_usb_dev_crash_shutdown(struct cnss_usb_data *usb_priv);
+int cnss_usb_dev_ramdump(struct cnss_usb_data *usb_priv);
+
+int cnss_usb_register_driver_hdlr(struct cnss_usb_data *usb_priv, void *data);
+
+int cnss_usb_unregister_driver_hdlr(struct cnss_usb_data *usb_priv);
+int cnss_usb_call_driver_modem_status(struct cnss_usb_data *usb_priv,
+ int modem_current_status);
+
+#endif /* _CNSS_USB_H */