Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3f4e727 authored by Chunfeng Yun's avatar Chunfeng Yun Committed by Greg Kroah-Hartman
Browse files

usb: mtu3: host only mode support



supports host only mode and the code is ported from
host/xhci-mtk.c
IPPC register shared between host and device is moved
into common glue layer.

Signed-off-by: default avatarChunfeng Yun <chunfeng.yun@mediatek.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a29de31b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ config USB_MTU3
	tristate "MediaTek USB3 Dual Role controller"
	depends on (USB || USB_GADGET) && HAS_DMA
	depends on ARCH_MEDIATEK || COMPILE_TEST
	select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD
	help
	  Say Y or M here if your system runs on MediaTek SoCs with
	  Dual Role SuperSpeed USB controller. You can select usb
@@ -18,8 +19,16 @@ config USB_MTU3
if USB_MTU3
choice
	bool "MTU3 Mode Selection"
	default USB_MTU3_HOST if (USB && !USB_GADGET)
	default USB_MTU3_GADGET if (!USB && USB_GADGET)

config USB_MTU3_HOST
	bool "Host only mode"
	depends on USB=y || USB=USB_MTU3
	help
	  Select this when you want to use MTU3 in host mode only,
	  thereby the gadget feature will be regressed.

config USB_MTU3_GADGET
	bool "Gadget only mode"
	depends on USB_GADGET=y || USB_GADGET=USB_MTU3
+10 −1
Original line number Diff line number Diff line
obj-$(CONFIG_USB_MTU3)	+= mtu3.o
mtu3-y	:= mtu3_plat.o mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o

mtu3-y	:= mtu3_plat.o

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

ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET)),)
	mtu3-y	+= mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o
endif
+41 −6
Original line number Diff line number Diff line
@@ -172,6 +172,40 @@ struct mtu3_gpd_ring {
	struct qmu_gpd *enqueue;
	struct qmu_gpd *dequeue;
};
/**
 * @mac_base: register base address of device MAC, exclude xHCI's
 * @ippc_base: register base address of ip port controller 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
 * @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
 */
struct ssusb_mtk {
	struct device *dev;
	struct mtu3 *u3d;
	void __iomem *mac_base;
	void __iomem *ippc_base;
	struct phy **phys;
	int num_phys;
	/* common power & clock */
	struct regulator *vusb33;
	struct clk *sys_clk;
	/* otg */
	enum usb_dr_mode dr_mode;
	bool is_host;
	int u2_ports;
	int u3_ports;
	/* usb wakeup for host mode */
	bool wakeup_en;
	struct clk *wk_deb_p0;
	struct clk *wk_deb_p1;
	struct regmap *pericfg;
};

/**
 * @fifo_size: it is (@slot + 1) * @fifo_seg_size
@@ -210,6 +244,11 @@ struct mtu3_request {
	int epnum;
};

static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev)
{
	return dev_get_drvdata(dev);
}

/**
 * struct mtu3 - device driver instance data.
 * @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP only,
@@ -222,12 +261,10 @@ struct mtu3_request {
 */
struct mtu3 {
	spinlock_t lock;
	struct ssusb_mtk *ssusb;
	struct device *dev;
	void __iomem *mac_base;
	void __iomem *ippc_base;
	struct phy *phy;
	struct regulator *vusb33;
	struct clk *sys_clk;
	int irq;

	struct mtu3_fifo_info tx_fifo;
@@ -320,7 +357,7 @@ static inline void mtu3_clrbits(void __iomem *base, u32 offset, u32 bits)
	writel((tmp & ~(bits)), addr);
}

int ssusb_check_clocks(struct mtu3 *mtu, u32 ex_clks);
int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks);
struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
void mtu3_free_request(struct usb_ep *ep, struct usb_request *req);
void mtu3_req_complete(struct mtu3_ep *mep,
@@ -341,8 +378,6 @@ void mtu3_gadget_reset(struct mtu3 *mtu);
void mtu3_gadget_suspend(struct mtu3 *mtu);
void mtu3_gadget_resume(struct mtu3 *mtu);
void mtu3_gadget_disconnect(struct mtu3 *mtu);
int ssusb_gadget_init(struct mtu3 *mtu);
void ssusb_gadget_exit(struct mtu3 *mtu);

irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu);
extern const struct usb_ep_ops mtu3_ep0_ops;
+36 −6
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ static int mtu3_device_enable(struct mtu3 *mtu)
		SSUSB_U2_PORT_HOST_SEL));
	mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);

	return ssusb_check_clocks(mtu, check_clk);
	return ssusb_check_clocks(mtu->ssusb, check_clk);
}

static void mtu3_device_disable(struct mtu3 *mtu)
@@ -765,11 +765,38 @@ static void mtu3_hw_exit(struct mtu3 *mtu)

/*-------------------------------------------------------------------------*/

int ssusb_gadget_init(struct mtu3 *mtu)
int ssusb_gadget_init(struct ssusb_mtk *ssusb)
{
	struct device *dev = mtu->dev;
	int ret;
	struct device *dev = ssusb->dev;
	struct platform_device *pdev = to_platform_device(dev);
	struct mtu3 *mtu = NULL;
	struct resource *res;
	int ret = -ENOMEM;

	mtu = devm_kzalloc(dev, sizeof(struct mtu3), GFP_KERNEL);
	if (mtu == NULL)
		return -ENOMEM;

	mtu->irq = platform_get_irq(pdev, 0);
	if (mtu->irq <= 0) {
		dev_err(dev, "fail to get irq number\n");
		return -ENODEV;
	}
	dev_info(dev, "irq %d\n", mtu->irq);

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac");
	mtu->mac_base = devm_ioremap_resource(dev, res);
	if (IS_ERR(mtu->mac_base)) {
		dev_err(dev, "error mapping memory for dev mac\n");
		return PTR_ERR(mtu->mac_base);
	}

	spin_lock_init(&mtu->lock);
	mtu->dev = dev;
	mtu->ippc_base = ssusb->ippc_base;
	ssusb->mac_base	= mtu->mac_base;
	ssusb->u3d = mtu;
	mtu->ssusb = ssusb;
	mtu->max_speed = usb_get_maximum_speed(dev);

	/* check the max_speed parameter */
@@ -820,14 +847,17 @@ int ssusb_gadget_init(struct mtu3 *mtu)

irq_err:
	mtu3_hw_exit(mtu);
	ssusb->u3d = NULL;
	dev_err(dev, " %s() fail...\n", __func__);

	return ret;
}

void ssusb_gadget_exit(struct mtu3 *mtu)
void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
{
	struct mtu3 *mtu = ssusb->u3d;

	mtu3_gadget_cleanup(mtu);
	device_init_wakeup(mtu->dev, false);
	device_init_wakeup(ssusb->dev, false);
	mtu3_hw_exit(mtu);
}
+85 −0
Original line number Diff line number Diff line
/*
 * mtu3_dr.h - dual role switch and host glue layer header
 *
 * Copyright (C) 2016 MediaTek Inc.
 *
 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef _MTU3_DR_H_
#define _MTU3_DR_H_

#if IS_ENABLED(CONFIG_USB_MTU3_HOST)

int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn);
void ssusb_host_exit(struct ssusb_mtk *ssusb);
int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
				struct device_node *dn);
int ssusb_host_enable(struct ssusb_mtk *ssusb);
int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend);
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb);
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb);

#else

static inline int ssusb_host_init(struct ssusb_mtk *ssusb,

	struct device_node *parent_dn)
{
	return 0;
}

static inline void ssusb_host_exit(struct ssusb_mtk *ssusb)
{}

static inline int ssusb_wakeup_of_property_parse(
	struct ssusb_mtk *ssusb, struct device_node *dn)
{
	return 0;
}

static inline int ssusb_host_enable(struct ssusb_mtk *ssusb)
{
	return 0;
}

static inline int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
{
	return 0;
}

static inline int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
{
	return 0;
}

static inline void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
{}

#endif


#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
int ssusb_gadget_init(struct ssusb_mtk *ssusb);
void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
#else
static inline int ssusb_gadget_init(struct ssusb_mtk *ssusb)
{
	return 0;
}

static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
{}
#endif

#endif		/* _MTU3_DR_H_ */
Loading