USB: gadget: composite: Move switch_set_state calls to a work queue

Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 03b0287..bf55532 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -545,7 +545,7 @@
 done:
 	usb_gadget_vbus_draw(gadget, power);
 
-	switch_set_state(&cdev->sdev, number);
+	schedule_work(&cdev->switch_work);
 
 	if (result >= 0 && cdev->delayed_status)
 		result = USB_GADGET_DELAYED_STATUS;
@@ -1118,7 +1118,7 @@
 		composite->disconnect(cdev);
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
-	switch_set_state(&cdev->sdev, 0);
+	schedule_work(&cdev->switch_work);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1199,6 +1199,19 @@
 	return *desc;
 }
 
+static void
+composite_switch_work(struct work_struct *data)
+{
+	struct usb_composite_dev	*cdev =
+		container_of(data, struct usb_composite_dev, switch_work);
+	struct usb_configuration *config = cdev->config;
+
+	if (config)
+		switch_set_state(&cdev->sdev, config->bConfigurationValue);
+	else
+		switch_set_state(&cdev->sdev, 0);
+}
+
 static int composite_bind(struct usb_gadget *gadget)
 {
 	struct usb_composite_dev	*cdev;
@@ -1252,6 +1265,7 @@
 	status = switch_dev_register(&cdev->sdev);
 	if (status < 0)
 		goto fail;
+	INIT_WORK(&cdev->switch_work, composite_switch_work);
 
 	cdev->desc = *composite->dev;
 	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 0b2d291..4cc4680 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -372,6 +372,7 @@
 	spinlock_t			lock;
 
 	struct switch_dev sdev;
+	struct work_struct switch_work;
 };
 
 extern int usb_string_id(struct usb_composite_dev *c);