Skip to content

Commit

Permalink
usb: mtu3: dual-role mode support
Browse files Browse the repository at this point in the history
support dual-role mode; there are two ways to switch between
host and device modes, one is by idpin, another is by debugfs
which depends on user input.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Chunfeng Yun authored and Greg Kroah-Hartman committed Oct 27, 2016
1 parent b3f4e72 commit d0ed062
Show file tree
Hide file tree
Showing 9 changed files with 557 additions and 21 deletions.
15 changes: 14 additions & 1 deletion drivers/usb/mtu3/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

config USB_MTU3
tristate "MediaTek USB3 Dual Role controller"
depends on (USB || USB_GADGET) && HAS_DMA
depends on EXTCON && (USB || USB_GADGET) && HAS_DMA
depends on ARCH_MEDIATEK || COMPILE_TEST
select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD
help
Expand All @@ -19,6 +19,7 @@ config USB_MTU3
if USB_MTU3
choice
bool "MTU3 Mode Selection"
default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET)
default USB_MTU3_HOST if (USB && !USB_GADGET)
default USB_MTU3_GADGET if (!USB && USB_GADGET)

Expand All @@ -36,6 +37,18 @@ config USB_MTU3_GADGET
Select this when you want to use MTU3 in gadget mode only,
thereby the host feature will be regressed.

config USB_MTU3_DUAL_ROLE
bool "Dual Role mode"
depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3))
help
This is the default mode of working of MTU3 controller where
both host and gadget features are enabled.

endchoice

config USB_MTU3_DEBUG
bool "Enable Debugging Messages"
help
Say Y here to enable debugging messages in the MTU3 Driver.

endif
11 changes: 9 additions & 2 deletions drivers/usb/mtu3/Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@

ccflags-$(CONFIG_USB_MTU3_DEBUG) += -DDEBUG

obj-$(CONFIG_USB_MTU3) += mtu3.o

mtu3-y := mtu3_plat.o

ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST)),)
ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
mtu3-y += mtu3_host.o
endif

ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET)),)
ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
mtu3-y += mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o
endif

ifneq ($(CONFIG_USB_MTU3_DUAL_ROLE),)
mtu3-y += mtu3_dr.o
endif
34 changes: 33 additions & 1 deletion drivers/usb/mtu3/mtu3.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/phy/phy.h>
Expand Down Expand Up @@ -172,15 +173,44 @@ struct mtu3_gpd_ring {
struct qmu_gpd *enqueue;
struct qmu_gpd *dequeue;
};

/**
* @vbus: vbus 5V used by host mode
* @edev: external connector used to detect vbus and iddig changes
* @vbus_nb: notifier for vbus detection
* @vbus_nb: notifier for iddig(idpin) detection
* @extcon_reg_dwork: delay work for extcon notifier register, waiting for
* xHCI driver initialization, it's necessary for system bootup
* as device.
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
* @id_*: used to maually switch between host and device modes by idpin
* @manual_drd_enabled: it's true when supports dual-role device by debugfs
* to switch host/device modes depending on user input.
*/
struct otg_switch_mtk {
struct regulator *vbus;
struct extcon_dev *edev;
struct notifier_block vbus_nb;
struct notifier_block id_nb;
struct delayed_work extcon_reg_dwork;
bool is_u3_drd;
/* dual-role switch by debugfs */
struct pinctrl *id_pinctrl;
struct pinctrl_state *id_float;
struct pinctrl_state *id_ground;
bool manual_drd_enabled;
};

/**
* @mac_base: register base address of device MAC, exclude xHCI's
* @ippc_base: register base address of ip port controller interface (IPPC)
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
* @sys_clk: system clock of mtu3, shared by device/host IP
* @dr_mode: works in which mode:
* host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports
* @u3_ports: number of usb3.0 host ports
* @dbgfs_root: only used when supports manual dual-role switch via debugfs
* @wakeup_en: it's true when supports remote wakeup in host mode
* @wk_deb_p0: port0's wakeup debounce clock
* @wk_deb_p1: it's optional, and depends on port1 is supported or not
Expand All @@ -196,10 +226,12 @@ struct ssusb_mtk {
struct regulator *vusb33;
struct clk *sys_clk;
/* otg */
struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode;
bool is_host;
int u2_ports;
int u3_ports;
struct dentry *dbgfs_root;
/* usb wakeup for host mode */
bool wakeup_en;
struct clk *wk_deb_p0;
Expand Down
14 changes: 5 additions & 9 deletions drivers/usb/mtu3/mtu3_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ static void mtu3_intr_disable(struct mtu3 *mtu)

/* Disable level 1 interrupts */
mtu3_writel(mbase, U3D_LV1IECR, ~0x0);

/* Disable endpoint interrupts */
mtu3_writel(mbase, U3D_EPIECR, ~0x0);
}
Expand All @@ -161,13 +160,10 @@ static void mtu3_intr_status_clear(struct mtu3 *mtu)

/* Clear EP0 and Tx/Rx EPn interrupts status */
mtu3_writel(mbase, U3D_EPISR, ~0x0);

/* Clear U2 USB common interrupts status */
mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);

/* Clear U3 LTSSM interrupts status */
mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);

/* Clear speed change interrupt status */
mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
}
Expand Down Expand Up @@ -268,7 +264,6 @@ void mtu3_start(struct mtu3 *mtu)

/* Initialize the default interrupts */
mtu3_intr_enable(mtu);

mtu->is_active = 1;

if (mtu->softconnect)
Expand Down Expand Up @@ -516,7 +511,6 @@ static int mtu3_mem_alloc(struct mtu3 *mtu)
mtu->out_eps = &ep_array[mtu->num_eps];
/* ep0 uses in_eps[0], out_eps[0] is reserved */
mtu->ep0 = mtu->in_eps;

mtu->ep0->mtu = mtu;
mtu->ep0->epnum = 0;

Expand Down Expand Up @@ -560,6 +554,7 @@ static void mtu3_set_speed(struct mtu3 *mtu)
/* HS/FS detected by HW */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
}

dev_info(mtu->dev, "max_speed: %s\n",
usb_speed_string(mtu->max_speed));
}
Expand All @@ -586,13 +581,10 @@ static void mtu3_regs_init(struct mtu3 *mtu)

/* delay about 0.1us from detecting reset to send chirp-K */
mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);

/* U2/U3 detected by HW */
mtu3_writel(mbase, U3D_DEVICE_CONF, 0);

/* enable QMU 16B checksum */
mtu3_setbits(mbase, U3D_QCR0, QMU_CS16B_EN);

/* vbus detected by HW */
mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
}
Expand Down Expand Up @@ -838,6 +830,10 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
goto gadget_err;
}

/* init as host mode, power down device IP for power saving */
if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
mtu3_stop(mtu);

dev_dbg(dev, " %s() done...\n", __func__);

return 0;
Expand Down
Loading

0 comments on commit d0ed062

Please sign in to comment.