Skip to content

Commit

Permalink
usb: musb: jz4740: Register USB role switch
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paul Cercueil authored and Greg Kroah-Hartman committed Mar 17, 2020
1 parent 57aadb4 commit 5004eaa
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/usb/musb/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
48 changes: 48 additions & 0 deletions drivers/usb/musb/jz4740.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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,
Expand Down

0 comments on commit 5004eaa

Please sign in to comment.