usb: gadget: Implement remote wakeup in mbim

Implement remote wake up in mbim.
Add required changes in ecm and rndis to comply to
a new structure of data_port in u_bam_data.

CRs-fixed: 396623
Change-Id: I2e182e78ed0fbd8524a3857f104b951ad5bdff4d
Signed-off-by: Anna Perel <aperel@codeaurora.org>
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 6883b78..7a84ca3 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -67,8 +67,8 @@
 };
 
 struct f_mbim {
-	struct usb_function function;
-	struct usb_composite_dev *cdev;
+	struct usb_function		function;
+	struct usb_composite_dev	*cdev;
 
 	atomic_t	online;
 	bool		is_open;
@@ -1255,6 +1255,20 @@
 	pr_info("mbim deactivated\n");
 }
 
+#define MBIM_ACTIVE_PORT	0
+
+static void mbim_suspend(struct usb_function *f)
+{
+	pr_info("mbim suspended\n");
+	bam_data_suspend(MBIM_ACTIVE_PORT);
+}
+
+static void mbim_resume(struct usb_function *f)
+{
+	pr_info("mbim resumed\n");
+	bam_data_resume(MBIM_ACTIVE_PORT);
+}
+
 /*---------------------- function driver setup/binding ---------------------*/
 
 static int
@@ -1288,6 +1302,8 @@
 	mbim_data_intf.bInterfaceNumber = status;
 	mbim_union_desc.bSlaveInterface0 = status;
 
+	mbim->bam_port.cdev = cdev;
+
 	status = -ENODEV;
 
 	/* allocate instance-specific endpoints */
@@ -1461,6 +1477,8 @@
 	mbim->function.get_alt = mbim_get_alt;
 	mbim->function.setup = mbim_setup;
 	mbim->function.disable = mbim_disable;
+	mbim->function.suspend = mbim_suspend;
+	mbim->function.resume = mbim_resume;
 
 	INIT_LIST_HEAD(&mbim->cpkt_req_q);
 	INIT_LIST_HEAD(&mbim->cpkt_resp_q);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 98a29ae..7fedaf6 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -305,7 +305,7 @@
 {
 	int ret;
 
-	ecm_qc_bam_port.func = dev->port.func;
+	ecm_qc_bam_port.cdev = dev->port.func.config->cdev;
 	ecm_qc_bam_port.in = dev->port.in_ep;
 	ecm_qc_bam_port.out = dev->port.out_ep;
 
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index a740d95..60b96fe 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -417,7 +417,7 @@
 {
 	int ret;
 
-	rndis_qc_bam_port.func = dev->port.func;
+	rndis_qc_bam_port.cdev = dev->port.func.config->cdev;
 	rndis_qc_bam_port.in = dev->port.in_ep;
 	rndis_qc_bam_port.out = dev->port.out_ep;
 
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index a105f5d..32f683e 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -35,7 +35,7 @@
 #define MSM_VENDOR_ID			BIT(16)
 
 struct data_port {
-	struct usb_function		func;
+	struct usb_composite_dev	*cdev;
 	struct usb_ep			*in;
 	struct usb_ep			*out;
 };
@@ -326,3 +326,54 @@
 	return ret;
 }
 
+static int bam_data_wake_cb(void *param)
+{
+	struct bam_data_port *port = (struct bam_data_port *)param;
+	struct data_port *d_port = port->port_usb;
+
+	pr_info("%s: woken up by peer\n", __func__);
+
+	if (!d_port) {
+		pr_err("FAILED: d_port == NULL");
+		return -ENODEV;
+	}
+
+	if (!d_port->cdev) {
+		pr_err("FAILED: d_port->cdev == NULL");
+		return -ENODEV;
+	}
+
+	if (!d_port->cdev->gadget) {
+		pr_err("FAILED: d_port->cdev->gadget == NULL");
+		return -ENODEV;
+	}
+
+	return usb_gadget_wakeup(d_port->cdev->gadget);
+}
+
+void bam_data_suspend(u8 port_num)
+{
+
+	struct bam_data_port	*port;
+	struct bam_data_ch_info *d;
+
+	port = bam2bam_data_ports[port_num];
+	d = &port->data_ch;
+
+	pr_info("%s: suspended port %d\n", __func__, port_num);
+	usb_bam_register_wake_cb(d->connection_idx, bam_data_wake_cb, port);
+}
+
+void bam_data_resume(u8 port_num)
+{
+
+	struct bam_data_port	*port;
+	struct bam_data_ch_info *d;
+
+	port = bam2bam_data_ports[port_num];
+	d = &port->data_ch;
+
+	pr_info("%s: resumed port %d\n", __func__, port_num);
+	usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+}
+