[PATCH v2 3/5] usb: musb: jz4740: Register USB role switch
From: Paul Cercueil <paul@crapouillou.net>
Date: 2020-02-24 01:40:38
Also in:
linux-usb, lkml
Subsystem:
ingenic jz47xx socs, musb multipoint high speed dual-role controller, the rest, usb subsystem · Maintainers:
Paul Cercueil, Bin Liu, Linus Torvalds, Greg Kroah-Hartman
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>
---
Notes:
v2: No change
drivers/usb/musb/Kconfig | 1 +
drivers/usb/musb/jz4740.c | 46 +++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index c4b349e074c1..3268adb7d7cf 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig@@ -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"
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index aa32b5af0c1f..bbfeb9881788 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c@@ -12,13 +12,16 @@ #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,38 @@ 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 device *dev, enum usb_role role) +{ + struct jz4740_glue *glue = dev_get_drvdata(dev); + 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, + .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 +118,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 +135,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,
--
2.25.0