usb: musb: jz4740: Register USB role switch
authorPaul Cercueil <paul@crapouillou.net>
Mon, 16 Mar 2020 21:11:32 +0000 (16:11 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Mar 2020 19:03:27 +0000 (20:03 +0100)
Register a USB role switch, in order to get notified by the connector
driver when the USB role changes. The notification is then transmitted
to the PHY.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: Bin Liu <b-liu@ti.com>
Link: https://lore.kernel.org/r/20200316211136.2274-5-b-liu@ti.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/musb/Kconfig
drivers/usb/musb/jz4740.c

index c4b349e074c157f2b5f473aa26216856b4a62ca4..3268adb7d7cf48c91bd8dad0470eee5dfac58ba3 100644 (file)
@@ -113,6 +113,7 @@ config USB_MUSB_JZ4740
        depends on MIPS || COMPILE_TEST
        depends on USB_MUSB_GADGET
        depends on USB=n || USB_OTG_BLACKLIST_HUB
+       select USB_ROLE_SWITCH
 
 config USB_MUSB_MEDIATEK
        tristate "MediaTek platforms"
index aa32b5af0c1f5fbd03fc7308611d564b96f8da8a..7f813bdaf1d16bdff15709478a47cd6a61ba406b 100644 (file)
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/usb/role.h>
 #include <linux/usb/usb_phy_generic.h>
 
 #include "musb_core.h"
 
 struct jz4740_glue {
        struct platform_device  *pdev;
+       struct musb             *musb;
        struct clk              *clk;
+       struct usb_role_switch  *role_sw;
 };
 
 static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
@@ -72,11 +75,40 @@ static const struct musb_hdrc_config jz4740_musb_config = {
        .fifo_cfg_size  = ARRAY_SIZE(jz4740_musb_fifo_cfg),
 };
 
+static int jz4740_musb_role_switch_set(struct usb_role_switch *sw,
+                                      enum usb_role role)
+{
+       struct jz4740_glue *glue = usb_role_switch_get_drvdata(sw);
+       struct usb_phy *phy = glue->musb->xceiv;
+
+       switch (role) {
+       case USB_ROLE_NONE:
+               atomic_notifier_call_chain(&phy->notifier, USB_EVENT_NONE, phy);
+               break;
+       case USB_ROLE_DEVICE:
+               atomic_notifier_call_chain(&phy->notifier, USB_EVENT_VBUS, phy);
+               break;
+       case USB_ROLE_HOST:
+               atomic_notifier_call_chain(&phy->notifier, USB_EVENT_ID, phy);
+               break;
+       }
+
+       return 0;
+}
+
 static int jz4740_musb_init(struct musb *musb)
 {
        struct device *dev = musb->controller->parent;
+       struct jz4740_glue *glue = dev_get_drvdata(dev);
+       struct usb_role_switch_desc role_sw_desc = {
+               .set = jz4740_musb_role_switch_set,
+               .driver_data = glue,
+               .fwnode = dev_fwnode(dev),
+       };
        int err;
 
+       glue->musb = musb;
+
        if (dev->of_node)
                musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
        else
@@ -88,6 +120,12 @@ static int jz4740_musb_init(struct musb *musb)
                return err;
        }
 
+       glue->role_sw = usb_role_switch_register(dev, &role_sw_desc);
+       if (IS_ERR(glue->role_sw)) {
+               dev_err(dev, "Failed to register USB role switch");
+               return PTR_ERR(glue->role_sw);
+       }
+
        /*
         * Silicon does not implement ConfigData register.
         * Set dyn_fifo to avoid reading EP config from hardware.
@@ -99,10 +137,20 @@ static int jz4740_musb_init(struct musb *musb)
        return 0;
 }
 
+static int jz4740_musb_exit(struct musb *musb)
+{
+       struct jz4740_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       usb_role_switch_unregister(glue->role_sw);
+
+       return 0;
+}
+
 static const struct musb_platform_ops jz4740_musb_ops = {
        .quirks         = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
        .fifo_mode      = 2,
        .init           = jz4740_musb_init,
+       .exit           = jz4740_musb_exit,
 #ifdef CONFIG_USB_INVENTRA_DMA
        .dma_init       = musbhs_dma_controller_create_noirq,
        .dma_exit       = musbhs_dma_controller_destroy,