]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
usb: renesas_usbhs: add suspend event support in gadget mode
authorVeeraiyan Chidambaram <veeraiyan.chidambaram@in.bosch.com>
Wed, 11 Sep 2019 13:15:56 +0000 (15:15 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 31 Dec 2019 11:36:56 +0000 (12:36 +0100)
[ Upstream commit 39abcc84846bbc0538f13c190b6a9c7e36890cd2 ]

When R-Car Gen3 USB 2.0 is in Gadget mode, if host is detached an interrupt
will be generated and Suspended state bit is set in interrupt status
register. Interrupt handler will call driver->suspend(composite_suspend)
if suspended state bit is set. composite_suspend will call
ffs_func_suspend which will post FUNCTIONFS_SUSPEND and will be consumed
by user space application via /dev/ep0.

To be able to detect host detach, extend the DVSQ_MASK to cover the
Suspended bit of the DVSQ[2:0] bitfield from the Interrupt Status
Register 0 (INTSTS0) register and perform appropriate action in the
DVST interrupt handler (usbhsg_irq_dev_state).

Without this commit, disconnection of the phone from R-Car-H3 ES2.0
Salvator-X CN9 port is not recognized and reverse role switch does
not happen. If phone is connected again it does not enumerate.

With this commit, disconnection will be recognized and reverse role
switch will happen by a user space application. If phone is connected
again it will enumerate properly and will become visible in the output
of 'lsusb'.

Signed-off-by: Veeraiyan Chidambaram <veeraiyan.chidambaram@in.bosch.com>
Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Link: https://lore.kernel.org/r/1568207756-22325-3-git-send-email-external.veeraiyan.c@de.adit-jv.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/usb/renesas_usbhs/common.h
drivers/usb/renesas_usbhs/mod_gadget.c

index b8620aa6b72e603abeeb85216438d6b0077abb30..8424c165f732aeb67748753375d43c8c16981c74 100644 (file)
@@ -163,11 +163,12 @@ struct usbhs_priv;
 #define VBSTS  (1 << 7)        /* VBUS_0 and VBUSIN_0 Input Status */
 #define VALID  (1 << 3)        /* USB Request Receive */
 
-#define DVSQ_MASK              (0x3 << 4)      /* Device State */
+#define DVSQ_MASK              (0x7 << 4)      /* Device State */
 #define  POWER_STATE           (0 << 4)
 #define  DEFAULT_STATE         (1 << 4)
 #define  ADDRESS_STATE         (2 << 4)
 #define  CONFIGURATION_STATE   (3 << 4)
+#define  SUSPENDED_STATE       (4 << 4)
 
 #define CTSQ_MASK              (0x7)   /* Control Transfer Stage */
 #define  IDLE_SETUP_STAGE      0       /* Idle stage or setup stage */
index 0dedb0d91dccb38e57d49599aaf010d73df9d4b9..b27f2135b66d76e9dc6750487cd2d87ac4c29d2c 100644 (file)
@@ -465,12 +465,18 @@ static int usbhsg_irq_dev_state(struct usbhs_priv *priv,
 {
        struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
        struct device *dev = usbhsg_gpriv_to_dev(gpriv);
+       int state = usbhs_status_get_device_state(irq_state);
 
        gpriv->gadget.speed = usbhs_bus_get_speed(priv);
 
-       dev_dbg(dev, "state = %x : speed : %d\n",
-               usbhs_status_get_device_state(irq_state),
-               gpriv->gadget.speed);
+       dev_dbg(dev, "state = %x : speed : %d\n", state, gpriv->gadget.speed);
+
+       if (gpriv->gadget.speed != USB_SPEED_UNKNOWN &&
+           (state & SUSPENDED_STATE)) {
+               if (gpriv->driver && gpriv->driver->suspend)
+                       gpriv->driver->suspend(&gpriv->gadget);
+               usb_gadget_set_state(&gpriv->gadget, USB_STATE_SUSPENDED);
+       }
 
        return 0;
 }