Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e6f91ba authored by Mayank Rana's avatar Mayank Rana
Browse files

usb: f_cdev: Retry USB function wakeup if USB is into low power mode



Consider case where USB is into low power mode after receiving USB
function suspend from host. To invoke function remote wakeup USB
controller is rerquired to bring out of low power mode. Hence once
USB controller and USB bus is resumed, perform USB function wakeup
from composite_resume() context to resume USB function on host side.

Change-Id: If15b70bc7d3781bc26bf593e3ee3edef621f72d7
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 7bdfe17c
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2011, 2013-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2011, 2013-2021, The Linux Foundation. All rights reserved.
 * Linux Foundation chooses to take subject only to the GPLv2 license terms,
 * and distributes only under these terms.
 *
@@ -110,6 +110,7 @@ struct f_cdev {
	/* function suspend status */
	bool			func_is_suspended;
	bool			func_wakeup_allowed;
	bool			func_wakeup_pending;

	struct cserial		port_usb;

@@ -530,10 +531,26 @@ static int usb_cser_set_alt(struct usb_function *f, unsigned int intf,
		}
	}

	port->func_wakeup_pending = false;
	usb_cser_connect(port);
	return rc;
}

static void usb_cser_resume(struct usb_function *f)
{
	struct f_cdev *port = func_to_port(f);
	struct usb_composite_dev *cdev = f->config->cdev;

	if (cdev->gadget->speed >= USB_SPEED_SUPER && port->func_is_suspended) {
		if (port->func_wakeup_pending) {
			dev_dbg(&cdev->gadget->dev,
				"func_wakeup for port:%s\n", port->name);
			usb_func_wakeup(&port->port_usb.func);
			port->func_wakeup_pending = false;
		}
	}
}

static int usb_cser_func_suspend(struct usb_function *f, u8 options)
{
	struct f_cdev	*port = func_to_port(f);
@@ -566,6 +583,7 @@ static void usb_cser_disable(struct usb_function *f)
		"port(%s) deactivated\n", port->name);

	usb_cser_disconnect(port);
	port->func_wakeup_pending = false;
	usb_ep_disable(port->port_usb.notify);
	port->port_usb.notify->driver_data = NULL;
}
@@ -1653,6 +1671,8 @@ static ssize_t cser_rw_write(struct file *file, const char __user *ubuf,
			port->func_is_suspended) {
			pr_debug("Calling usb_func_wakeup\n");
			ret = usb_func_wakeup(func);
			if (ret == -EAGAIN)
				port->func_wakeup_pending = true;
		} else {
			pr_debug("Calling usb_gadget_wakeup\n");
			ret = usb_gadget_wakeup(gadget);
@@ -2047,6 +2067,7 @@ static struct usb_function *cser_alloc(struct usb_function_instance *fi)
	port->port_usb.func.disable = usb_cser_disable;
	port->port_usb.func.setup = usb_cser_setup;
	port->port_usb.func.func_suspend = usb_cser_func_suspend;
	port->port_usb.func.resume = usb_cser_resume;
	port->port_usb.func.get_status = usb_cser_get_status;
	port->port_usb.func.free_func = usb_cser_free_func;