xref: /openbmc/linux/drivers/mfd/omap-usb-host.c (revision d7eaf866)
117cdd29dSKeshava Munegowda /**
217cdd29dSKeshava Munegowda  * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
317cdd29dSKeshava Munegowda  *
417cdd29dSKeshava Munegowda  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
517cdd29dSKeshava Munegowda  * Author: Keshava Munegowda <keshava_mgowda@ti.com>
617cdd29dSKeshava Munegowda  *
717cdd29dSKeshava Munegowda  * This program is free software: you can redistribute it and/or modify
817cdd29dSKeshava Munegowda  * it under the terms of the GNU General Public License version 2  of
917cdd29dSKeshava Munegowda  * the License as published by the Free Software Foundation.
1017cdd29dSKeshava Munegowda  *
1117cdd29dSKeshava Munegowda  * This program is distributed in the hope that it will be useful,
1217cdd29dSKeshava Munegowda  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1317cdd29dSKeshava Munegowda  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1417cdd29dSKeshava Munegowda  * GNU General Public License for more details.
1517cdd29dSKeshava Munegowda  *
1617cdd29dSKeshava Munegowda  * You should have received a copy of the GNU General Public License
1717cdd29dSKeshava Munegowda  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1817cdd29dSKeshava Munegowda  */
1917cdd29dSKeshava Munegowda #include <linux/kernel.h>
20417e206bSMing Lei #include <linux/module.h>
2117cdd29dSKeshava Munegowda #include <linux/types.h>
2217cdd29dSKeshava Munegowda #include <linux/slab.h>
2317cdd29dSKeshava Munegowda #include <linux/delay.h>
2417cdd29dSKeshava Munegowda #include <linux/clk.h>
2517cdd29dSKeshava Munegowda #include <linux/dma-mapping.h>
2617cdd29dSKeshava Munegowda #include <linux/spinlock.h>
27c05995c3SRuss Dill #include <linux/gpio.h>
28e8c4a7acSFelipe Balbi #include <linux/platform_device.h>
29e8c4a7acSFelipe Balbi #include <linux/platform_data/usb-omap.h>
301e7fe1a9SKeshava Munegowda #include <linux/pm_runtime.h>
3117cdd29dSKeshava Munegowda 
32e8c4a7acSFelipe Balbi #include "omap-usb.h"
33e8c4a7acSFelipe Balbi 
34a6d3a662SKeshava Munegowda #define USBHS_DRIVER_NAME	"usbhs_omap"
3517cdd29dSKeshava Munegowda #define OMAP_EHCI_DEVICE	"ehci-omap"
3617cdd29dSKeshava Munegowda #define OMAP_OHCI_DEVICE	"ohci-omap3"
3717cdd29dSKeshava Munegowda 
3817cdd29dSKeshava Munegowda /* OMAP USBHOST Register addresses  */
3917cdd29dSKeshava Munegowda 
4017cdd29dSKeshava Munegowda /* UHH Register Set */
4117cdd29dSKeshava Munegowda #define	OMAP_UHH_REVISION				(0x00)
4217cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG				(0x10)
4317cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG_MIDLEMODE			(1 << 12)
4417cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG_CACTIVITY			(1 << 8)
4517cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG_SIDLEMODE			(1 << 3)
4617cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG_ENAWAKEUP			(1 << 2)
4717cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG_SOFTRESET			(1 << 1)
4817cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSCONFIG_AUTOIDLE			(1 << 0)
4917cdd29dSKeshava Munegowda 
5017cdd29dSKeshava Munegowda #define	OMAP_UHH_SYSSTATUS				(0x14)
5117cdd29dSKeshava Munegowda #define	OMAP_UHH_HOSTCONFIG				(0x40)
5217cdd29dSKeshava Munegowda #define	OMAP_UHH_HOSTCONFIG_ULPI_BYPASS			(1 << 0)
5317cdd29dSKeshava Munegowda #define	OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS		(1 << 0)
5417cdd29dSKeshava Munegowda #define	OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS		(1 << 11)
5517cdd29dSKeshava Munegowda #define	OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS		(1 << 12)
5617cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN		(1 << 2)
5717cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN		(1 << 3)
5817cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN		(1 << 4)
5917cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN		(1 << 5)
6017cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS		(1 << 8)
6117cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS		(1 << 9)
6217cdd29dSKeshava Munegowda #define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS		(1 << 10)
6317cdd29dSKeshava Munegowda #define OMAP4_UHH_HOSTCONFIG_APP_START_CLK		(1 << 31)
6417cdd29dSKeshava Munegowda 
6517cdd29dSKeshava Munegowda /* OMAP4-specific defines */
6617cdd29dSKeshava Munegowda #define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR		(3 << 2)
6717cdd29dSKeshava Munegowda #define OMAP4_UHH_SYSCONFIG_NOIDLE			(1 << 2)
6817cdd29dSKeshava Munegowda #define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR		(3 << 4)
6917cdd29dSKeshava Munegowda #define OMAP4_UHH_SYSCONFIG_NOSTDBY			(1 << 4)
7017cdd29dSKeshava Munegowda #define OMAP4_UHH_SYSCONFIG_SOFTRESET			(1 << 0)
7117cdd29dSKeshava Munegowda 
7217cdd29dSKeshava Munegowda #define OMAP4_P1_MODE_CLEAR				(3 << 16)
7317cdd29dSKeshava Munegowda #define OMAP4_P1_MODE_TLL				(1 << 16)
7417cdd29dSKeshava Munegowda #define OMAP4_P1_MODE_HSIC				(3 << 16)
7517cdd29dSKeshava Munegowda #define OMAP4_P2_MODE_CLEAR				(3 << 18)
7617cdd29dSKeshava Munegowda #define OMAP4_P2_MODE_TLL				(1 << 18)
7717cdd29dSKeshava Munegowda #define OMAP4_P2_MODE_HSIC				(3 << 18)
7817cdd29dSKeshava Munegowda 
7917cdd29dSKeshava Munegowda #define	OMAP_UHH_DEBUG_CSR				(0x44)
8017cdd29dSKeshava Munegowda 
8117cdd29dSKeshava Munegowda /* Values of UHH_REVISION - Note: these are not given in the TRM */
8217cdd29dSKeshava Munegowda #define OMAP_USBHS_REV1		0x00000010	/* OMAP3 */
8317cdd29dSKeshava Munegowda #define OMAP_USBHS_REV2		0x50700100	/* OMAP4 */
8417cdd29dSKeshava Munegowda 
8517cdd29dSKeshava Munegowda #define is_omap_usbhs_rev1(x)	(x->usbhs_rev == OMAP_USBHS_REV1)
8617cdd29dSKeshava Munegowda #define is_omap_usbhs_rev2(x)	(x->usbhs_rev == OMAP_USBHS_REV2)
8717cdd29dSKeshava Munegowda 
8817cdd29dSKeshava Munegowda #define is_ehci_phy_mode(x)	(x == OMAP_EHCI_PORT_MODE_PHY)
8917cdd29dSKeshava Munegowda #define is_ehci_tll_mode(x)	(x == OMAP_EHCI_PORT_MODE_TLL)
9017cdd29dSKeshava Munegowda #define is_ehci_hsic_mode(x)	(x == OMAP_EHCI_PORT_MODE_HSIC)
9117cdd29dSKeshava Munegowda 
9217cdd29dSKeshava Munegowda 
9317cdd29dSKeshava Munegowda struct usbhs_hcd_omap {
94d7eaf866SRoger Quadros 	int				nports;
95d7eaf866SRoger Quadros 
9617cdd29dSKeshava Munegowda 	struct clk			*xclk60mhsp1_ck;
9717cdd29dSKeshava Munegowda 	struct clk			*xclk60mhsp2_ck;
9817cdd29dSKeshava Munegowda 	struct clk			*utmi_p1_fck;
9917cdd29dSKeshava Munegowda 	struct clk			*usbhost_p1_fck;
10017cdd29dSKeshava Munegowda 	struct clk			*utmi_p2_fck;
10117cdd29dSKeshava Munegowda 	struct clk			*usbhost_p2_fck;
10217cdd29dSKeshava Munegowda 	struct clk			*init_60m_fclk;
1031e7fe1a9SKeshava Munegowda 	struct clk			*ehci_logic_fck;
10417cdd29dSKeshava Munegowda 
10517cdd29dSKeshava Munegowda 	void __iomem			*uhh_base;
10617cdd29dSKeshava Munegowda 
1079d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata;
10817cdd29dSKeshava Munegowda 
10917cdd29dSKeshava Munegowda 	u32				usbhs_rev;
11017cdd29dSKeshava Munegowda 	spinlock_t			lock;
11117cdd29dSKeshava Munegowda };
11217cdd29dSKeshava Munegowda /*-------------------------------------------------------------------------*/
11317cdd29dSKeshava Munegowda 
11417cdd29dSKeshava Munegowda const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
115cbb8c220SGovindraj.R static u64 usbhs_dmamask = DMA_BIT_MASK(32);
11617cdd29dSKeshava Munegowda 
11717cdd29dSKeshava Munegowda /*-------------------------------------------------------------------------*/
11817cdd29dSKeshava Munegowda 
11917cdd29dSKeshava Munegowda static inline void usbhs_write(void __iomem *base, u32 reg, u32 val)
12017cdd29dSKeshava Munegowda {
12117cdd29dSKeshava Munegowda 	__raw_writel(val, base + reg);
12217cdd29dSKeshava Munegowda }
12317cdd29dSKeshava Munegowda 
12417cdd29dSKeshava Munegowda static inline u32 usbhs_read(void __iomem *base, u32 reg)
12517cdd29dSKeshava Munegowda {
12617cdd29dSKeshava Munegowda 	return __raw_readl(base + reg);
12717cdd29dSKeshava Munegowda }
12817cdd29dSKeshava Munegowda 
12917cdd29dSKeshava Munegowda static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val)
13017cdd29dSKeshava Munegowda {
13117cdd29dSKeshava Munegowda 	__raw_writeb(val, base + reg);
13217cdd29dSKeshava Munegowda }
13317cdd29dSKeshava Munegowda 
13417cdd29dSKeshava Munegowda static inline u8 usbhs_readb(void __iomem *base, u8 reg)
13517cdd29dSKeshava Munegowda {
13617cdd29dSKeshava Munegowda 	return __raw_readb(base + reg);
13717cdd29dSKeshava Munegowda }
13817cdd29dSKeshava Munegowda 
13917cdd29dSKeshava Munegowda /*-------------------------------------------------------------------------*/
14017cdd29dSKeshava Munegowda 
14117cdd29dSKeshava Munegowda static struct platform_device *omap_usbhs_alloc_child(const char *name,
14217cdd29dSKeshava Munegowda 			struct resource	*res, int num_resources, void *pdata,
14317cdd29dSKeshava Munegowda 			size_t pdata_size, struct device *dev)
14417cdd29dSKeshava Munegowda {
14517cdd29dSKeshava Munegowda 	struct platform_device	*child;
14617cdd29dSKeshava Munegowda 	int			ret;
14717cdd29dSKeshava Munegowda 
14817cdd29dSKeshava Munegowda 	child = platform_device_alloc(name, 0);
14917cdd29dSKeshava Munegowda 
15017cdd29dSKeshava Munegowda 	if (!child) {
15117cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_alloc %s failed\n", name);
15217cdd29dSKeshava Munegowda 		goto err_end;
15317cdd29dSKeshava Munegowda 	}
15417cdd29dSKeshava Munegowda 
15517cdd29dSKeshava Munegowda 	ret = platform_device_add_resources(child, res, num_resources);
15617cdd29dSKeshava Munegowda 	if (ret) {
15717cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_add_resources failed\n");
15817cdd29dSKeshava Munegowda 		goto err_alloc;
15917cdd29dSKeshava Munegowda 	}
16017cdd29dSKeshava Munegowda 
16117cdd29dSKeshava Munegowda 	ret = platform_device_add_data(child, pdata, pdata_size);
16217cdd29dSKeshava Munegowda 	if (ret) {
16317cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_add_data failed\n");
16417cdd29dSKeshava Munegowda 		goto err_alloc;
16517cdd29dSKeshava Munegowda 	}
16617cdd29dSKeshava Munegowda 
16717cdd29dSKeshava Munegowda 	child->dev.dma_mask		= &usbhs_dmamask;
168cbb8c220SGovindraj.R 	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
16917cdd29dSKeshava Munegowda 	child->dev.parent		= dev;
17017cdd29dSKeshava Munegowda 
17117cdd29dSKeshava Munegowda 	ret = platform_device_add(child);
17217cdd29dSKeshava Munegowda 	if (ret) {
17317cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_add failed\n");
17417cdd29dSKeshava Munegowda 		goto err_alloc;
17517cdd29dSKeshava Munegowda 	}
17617cdd29dSKeshava Munegowda 
17717cdd29dSKeshava Munegowda 	return child;
17817cdd29dSKeshava Munegowda 
17917cdd29dSKeshava Munegowda err_alloc:
18017cdd29dSKeshava Munegowda 	platform_device_put(child);
18117cdd29dSKeshava Munegowda 
18217cdd29dSKeshava Munegowda err_end:
18317cdd29dSKeshava Munegowda 	return NULL;
18417cdd29dSKeshava Munegowda }
18517cdd29dSKeshava Munegowda 
18617cdd29dSKeshava Munegowda static int omap_usbhs_alloc_children(struct platform_device *pdev)
18717cdd29dSKeshava Munegowda {
18817cdd29dSKeshava Munegowda 	struct device				*dev = &pdev->dev;
1899d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data		*pdata = dev->platform_data;
19017cdd29dSKeshava Munegowda 	struct platform_device			*ehci;
19117cdd29dSKeshava Munegowda 	struct platform_device			*ohci;
19217cdd29dSKeshava Munegowda 	struct resource				*res;
19317cdd29dSKeshava Munegowda 	struct resource				resources[2];
19417cdd29dSKeshava Munegowda 	int					ret;
19517cdd29dSKeshava Munegowda 
19617cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
19717cdd29dSKeshava Munegowda 	if (!res) {
19817cdd29dSKeshava Munegowda 		dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
19917cdd29dSKeshava Munegowda 		ret = -ENODEV;
20017cdd29dSKeshava Munegowda 		goto err_end;
20117cdd29dSKeshava Munegowda 	}
20217cdd29dSKeshava Munegowda 	resources[0] = *res;
20317cdd29dSKeshava Munegowda 
20417cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq");
20517cdd29dSKeshava Munegowda 	if (!res) {
20617cdd29dSKeshava Munegowda 		dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n");
20717cdd29dSKeshava Munegowda 		ret = -ENODEV;
20817cdd29dSKeshava Munegowda 		goto err_end;
20917cdd29dSKeshava Munegowda 	}
21017cdd29dSKeshava Munegowda 	resources[1] = *res;
21117cdd29dSKeshava Munegowda 
2129d9c6ae7SRoger Quadros 	ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
2139d9c6ae7SRoger Quadros 		sizeof(*pdata), dev);
21417cdd29dSKeshava Munegowda 
21517cdd29dSKeshava Munegowda 	if (!ehci) {
21617cdd29dSKeshava Munegowda 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
217d910774fSAxel Lin 		ret = -ENOMEM;
21817cdd29dSKeshava Munegowda 		goto err_end;
21917cdd29dSKeshava Munegowda 	}
22017cdd29dSKeshava Munegowda 
22117cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci");
22217cdd29dSKeshava Munegowda 	if (!res) {
22317cdd29dSKeshava Munegowda 		dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n");
22417cdd29dSKeshava Munegowda 		ret = -ENODEV;
22517cdd29dSKeshava Munegowda 		goto err_ehci;
22617cdd29dSKeshava Munegowda 	}
22717cdd29dSKeshava Munegowda 	resources[0] = *res;
22817cdd29dSKeshava Munegowda 
22917cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq");
23017cdd29dSKeshava Munegowda 	if (!res) {
23117cdd29dSKeshava Munegowda 		dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n");
23217cdd29dSKeshava Munegowda 		ret = -ENODEV;
23317cdd29dSKeshava Munegowda 		goto err_ehci;
23417cdd29dSKeshava Munegowda 	}
23517cdd29dSKeshava Munegowda 	resources[1] = *res;
23617cdd29dSKeshava Munegowda 
2379d9c6ae7SRoger Quadros 	ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
2389d9c6ae7SRoger Quadros 		sizeof(*pdata), dev);
23917cdd29dSKeshava Munegowda 	if (!ohci) {
24017cdd29dSKeshava Munegowda 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
241d910774fSAxel Lin 		ret = -ENOMEM;
24217cdd29dSKeshava Munegowda 		goto err_ehci;
24317cdd29dSKeshava Munegowda 	}
24417cdd29dSKeshava Munegowda 
24517cdd29dSKeshava Munegowda 	return 0;
24617cdd29dSKeshava Munegowda 
24717cdd29dSKeshava Munegowda err_ehci:
248d910774fSAxel Lin 	platform_device_unregister(ehci);
24917cdd29dSKeshava Munegowda 
25017cdd29dSKeshava Munegowda err_end:
25117cdd29dSKeshava Munegowda 	return ret;
25217cdd29dSKeshava Munegowda }
25317cdd29dSKeshava Munegowda 
25417cdd29dSKeshava Munegowda static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
25517cdd29dSKeshava Munegowda {
25617cdd29dSKeshava Munegowda 	switch (pmode) {
25717cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
25817cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
25917cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
26017cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
26117cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
26217cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
26317cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
26417cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
26517cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
26617cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
26717cdd29dSKeshava Munegowda 		return true;
26817cdd29dSKeshava Munegowda 
26917cdd29dSKeshava Munegowda 	default:
27017cdd29dSKeshava Munegowda 		return false;
27117cdd29dSKeshava Munegowda 	}
27217cdd29dSKeshava Munegowda }
27317cdd29dSKeshava Munegowda 
2741e7fe1a9SKeshava Munegowda static int usbhs_runtime_resume(struct device *dev)
27517cdd29dSKeshava Munegowda {
27617cdd29dSKeshava Munegowda 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
2779d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
2781e7fe1a9SKeshava Munegowda 	unsigned long			flags;
27917cdd29dSKeshava Munegowda 
2801e7fe1a9SKeshava Munegowda 	dev_dbg(dev, "usbhs_runtime_resume\n");
2811e7fe1a9SKeshava Munegowda 
2824dc2ccebSKeshava Munegowda 	omap_tll_enable();
28317cdd29dSKeshava Munegowda 	spin_lock_irqsave(&omap->lock, flags);
28417cdd29dSKeshava Munegowda 
2851e7fe1a9SKeshava Munegowda 	if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
2861e7fe1a9SKeshava Munegowda 		clk_enable(omap->ehci_logic_fck);
2871e7fe1a9SKeshava Munegowda 
288760189b3SKeshava Munegowda 	if (is_ehci_tll_mode(pdata->port_mode[0]))
2891e7fe1a9SKeshava Munegowda 		clk_enable(omap->usbhost_p1_fck);
290760189b3SKeshava Munegowda 	if (is_ehci_tll_mode(pdata->port_mode[1]))
2911e7fe1a9SKeshava Munegowda 		clk_enable(omap->usbhost_p2_fck);
292760189b3SKeshava Munegowda 
2931e7fe1a9SKeshava Munegowda 	clk_enable(omap->utmi_p1_fck);
2941e7fe1a9SKeshava Munegowda 	clk_enable(omap->utmi_p2_fck);
2951e7fe1a9SKeshava Munegowda 
2961e7fe1a9SKeshava Munegowda 	spin_unlock_irqrestore(&omap->lock, flags);
2971e7fe1a9SKeshava Munegowda 
2981e7fe1a9SKeshava Munegowda 	return 0;
2991e7fe1a9SKeshava Munegowda }
3001e7fe1a9SKeshava Munegowda 
3011e7fe1a9SKeshava Munegowda static int usbhs_runtime_suspend(struct device *dev)
3021e7fe1a9SKeshava Munegowda {
3031e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
3049d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
3051e7fe1a9SKeshava Munegowda 	unsigned long			flags;
3061e7fe1a9SKeshava Munegowda 
3071e7fe1a9SKeshava Munegowda 	dev_dbg(dev, "usbhs_runtime_suspend\n");
3081e7fe1a9SKeshava Munegowda 
3091e7fe1a9SKeshava Munegowda 	spin_lock_irqsave(&omap->lock, flags);
3101e7fe1a9SKeshava Munegowda 
311760189b3SKeshava Munegowda 	if (is_ehci_tll_mode(pdata->port_mode[0]))
3121e7fe1a9SKeshava Munegowda 		clk_disable(omap->usbhost_p1_fck);
313760189b3SKeshava Munegowda 	if (is_ehci_tll_mode(pdata->port_mode[1]))
3141e7fe1a9SKeshava Munegowda 		clk_disable(omap->usbhost_p2_fck);
315760189b3SKeshava Munegowda 
3161e7fe1a9SKeshava Munegowda 	clk_disable(omap->utmi_p2_fck);
3171e7fe1a9SKeshava Munegowda 	clk_disable(omap->utmi_p1_fck);
3181e7fe1a9SKeshava Munegowda 
3191e7fe1a9SKeshava Munegowda 	if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
3201e7fe1a9SKeshava Munegowda 		clk_disable(omap->ehci_logic_fck);
3211e7fe1a9SKeshava Munegowda 
3221e7fe1a9SKeshava Munegowda 	spin_unlock_irqrestore(&omap->lock, flags);
3234dc2ccebSKeshava Munegowda 	omap_tll_disable();
3241e7fe1a9SKeshava Munegowda 
3251e7fe1a9SKeshava Munegowda 	return 0;
3261e7fe1a9SKeshava Munegowda }
3271e7fe1a9SKeshava Munegowda 
3281e7fe1a9SKeshava Munegowda static void omap_usbhs_init(struct device *dev)
3291e7fe1a9SKeshava Munegowda {
3301e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
3319d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
3321e7fe1a9SKeshava Munegowda 	unsigned long			flags;
3331e7fe1a9SKeshava Munegowda 	unsigned			reg;
3341e7fe1a9SKeshava Munegowda 
3351e7fe1a9SKeshava Munegowda 	dev_dbg(dev, "starting TI HSUSB Controller\n");
3361e7fe1a9SKeshava Munegowda 
3379d9c6ae7SRoger Quadros 	if (pdata->phy_reset) {
3389d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
3399d9c6ae7SRoger Quadros 			gpio_request_one(pdata->reset_gpio_port[0],
340c05995c3SRuss Dill 					 GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
341c05995c3SRuss Dill 
3429d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
3439d9c6ae7SRoger Quadros 			gpio_request_one(pdata->reset_gpio_port[1],
344c05995c3SRuss Dill 					 GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
345c05995c3SRuss Dill 
346c05995c3SRuss Dill 		/* Hold the PHY in RESET for enough time till DIR is high */
347c05995c3SRuss Dill 		udelay(10);
348c05995c3SRuss Dill 	}
349c05995c3SRuss Dill 
350760189b3SKeshava Munegowda 	pm_runtime_get_sync(dev);
351c05995c3SRuss Dill 	spin_lock_irqsave(&omap->lock, flags);
35217cdd29dSKeshava Munegowda 
35317cdd29dSKeshava Munegowda 	reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
35417cdd29dSKeshava Munegowda 	/* setup ULPI bypass and burst configurations */
35517cdd29dSKeshava Munegowda 	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
35617cdd29dSKeshava Munegowda 			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
35717cdd29dSKeshava Munegowda 			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
35817cdd29dSKeshava Munegowda 	reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
35917cdd29dSKeshava Munegowda 	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
36017cdd29dSKeshava Munegowda 
36117cdd29dSKeshava Munegowda 	if (is_omap_usbhs_rev1(omap)) {
36217cdd29dSKeshava Munegowda 		if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED)
36317cdd29dSKeshava Munegowda 			reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
36417cdd29dSKeshava Munegowda 		if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED)
36517cdd29dSKeshava Munegowda 			reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
36617cdd29dSKeshava Munegowda 		if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED)
36717cdd29dSKeshava Munegowda 			reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
36817cdd29dSKeshava Munegowda 
36917cdd29dSKeshava Munegowda 		/* Bypass the TLL module for PHY mode operation */
37063b68901SRoger Quadros 		if (pdata->single_ulpi_bypass) {
37117cdd29dSKeshava Munegowda 			dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
37217cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[0]) ||
37317cdd29dSKeshava Munegowda 				is_ehci_phy_mode(pdata->port_mode[1]) ||
37417cdd29dSKeshava Munegowda 					is_ehci_phy_mode(pdata->port_mode[2]))
37517cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
37617cdd29dSKeshava Munegowda 			else
37717cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
37817cdd29dSKeshava Munegowda 		} else {
37917cdd29dSKeshava Munegowda 			dev_dbg(dev, "OMAP3 ES version > ES2.1\n");
38017cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[0]))
38117cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
38217cdd29dSKeshava Munegowda 			else
38317cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
38417cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[1]))
38517cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
38617cdd29dSKeshava Munegowda 			else
38717cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
38817cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[2]))
38917cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
39017cdd29dSKeshava Munegowda 			else
39117cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
39217cdd29dSKeshava Munegowda 		}
39317cdd29dSKeshava Munegowda 	} else if (is_omap_usbhs_rev2(omap)) {
39417cdd29dSKeshava Munegowda 		/* Clear port mode fields for PHY mode*/
39517cdd29dSKeshava Munegowda 		reg &= ~OMAP4_P1_MODE_CLEAR;
39617cdd29dSKeshava Munegowda 		reg &= ~OMAP4_P2_MODE_CLEAR;
39717cdd29dSKeshava Munegowda 
39817cdd29dSKeshava Munegowda 		if (is_ehci_tll_mode(pdata->port_mode[0]) ||
39917cdd29dSKeshava Munegowda 			(is_ohci_port(pdata->port_mode[0])))
40017cdd29dSKeshava Munegowda 			reg |= OMAP4_P1_MODE_TLL;
40117cdd29dSKeshava Munegowda 		else if (is_ehci_hsic_mode(pdata->port_mode[0]))
40217cdd29dSKeshava Munegowda 			reg |= OMAP4_P1_MODE_HSIC;
40317cdd29dSKeshava Munegowda 
40417cdd29dSKeshava Munegowda 		if (is_ehci_tll_mode(pdata->port_mode[1]) ||
40517cdd29dSKeshava Munegowda 			(is_ohci_port(pdata->port_mode[1])))
40617cdd29dSKeshava Munegowda 			reg |= OMAP4_P2_MODE_TLL;
40717cdd29dSKeshava Munegowda 		else if (is_ehci_hsic_mode(pdata->port_mode[1]))
40817cdd29dSKeshava Munegowda 			reg |= OMAP4_P2_MODE_HSIC;
40917cdd29dSKeshava Munegowda 	}
41017cdd29dSKeshava Munegowda 
41117cdd29dSKeshava Munegowda 	usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
41217cdd29dSKeshava Munegowda 	dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
41317cdd29dSKeshava Munegowda 
414d11536e4SAxel Lin 	spin_unlock_irqrestore(&omap->lock, flags);
415c05995c3SRuss Dill 
416760189b3SKeshava Munegowda 	pm_runtime_put_sync(dev);
4179d9c6ae7SRoger Quadros 	if (pdata->phy_reset) {
418c05995c3SRuss Dill 		/* Hold the PHY in RESET for enough time till
419c05995c3SRuss Dill 		 * PHY is settled and ready
420c05995c3SRuss Dill 		 */
421c05995c3SRuss Dill 		udelay(10);
422c05995c3SRuss Dill 
4239d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
424c05995c3SRuss Dill 			gpio_set_value_cansleep
4259d9c6ae7SRoger Quadros 				(pdata->reset_gpio_port[0], 1);
426c05995c3SRuss Dill 
4279d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
428c05995c3SRuss Dill 			gpio_set_value_cansleep
4299d9c6ae7SRoger Quadros 				(pdata->reset_gpio_port[1], 1);
430c05995c3SRuss Dill 	}
43117cdd29dSKeshava Munegowda }
4328f2df014SKeshava Munegowda 
433c05995c3SRuss Dill static void omap_usbhs_deinit(struct device *dev)
434c05995c3SRuss Dill {
435c05995c3SRuss Dill 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
4369d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
437c05995c3SRuss Dill 
4389d9c6ae7SRoger Quadros 	if (pdata->phy_reset) {
4399d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
4409d9c6ae7SRoger Quadros 			gpio_free(pdata->reset_gpio_port[0]);
441c05995c3SRuss Dill 
4429d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
4439d9c6ae7SRoger Quadros 			gpio_free(pdata->reset_gpio_port[1]);
444c05995c3SRuss Dill 	}
445c05995c3SRuss Dill }
446c05995c3SRuss Dill 
4471e7fe1a9SKeshava Munegowda 
4481e7fe1a9SKeshava Munegowda /**
4491e7fe1a9SKeshava Munegowda  * usbhs_omap_probe - initialize TI-based HCDs
4501e7fe1a9SKeshava Munegowda  *
4511e7fe1a9SKeshava Munegowda  * Allocates basic resources for this USB host controller.
4521e7fe1a9SKeshava Munegowda  */
453f791be49SBill Pemberton static int usbhs_omap_probe(struct platform_device *pdev)
45417cdd29dSKeshava Munegowda {
4551e7fe1a9SKeshava Munegowda 	struct device			*dev =  &pdev->dev;
4561e7fe1a9SKeshava Munegowda 	struct usbhs_omap_platform_data	*pdata = dev->platform_data;
4571e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap		*omap;
4581e7fe1a9SKeshava Munegowda 	struct resource			*res;
4591e7fe1a9SKeshava Munegowda 	int				ret = 0;
4601e7fe1a9SKeshava Munegowda 	int				i;
46117cdd29dSKeshava Munegowda 
4621e7fe1a9SKeshava Munegowda 	if (!pdata) {
4631e7fe1a9SKeshava Munegowda 		dev_err(dev, "Missing platform data\n");
46427d4f2c6SRoger Quadros 		return -ENODEV;
46517cdd29dSKeshava Munegowda 	}
4661e7fe1a9SKeshava Munegowda 
46727d4f2c6SRoger Quadros 	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
4681e7fe1a9SKeshava Munegowda 	if (!omap) {
4691e7fe1a9SKeshava Munegowda 		dev_err(dev, "Memory allocation failed\n");
47027d4f2c6SRoger Quadros 		return -ENOMEM;
47127d4f2c6SRoger Quadros 	}
47227d4f2c6SRoger Quadros 
47327d4f2c6SRoger Quadros 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
47427d4f2c6SRoger Quadros 	omap->uhh_base = devm_request_and_ioremap(dev, res);
47527d4f2c6SRoger Quadros 	if (!omap->uhh_base) {
47627d4f2c6SRoger Quadros 		dev_err(dev, "Resource request/ioremap failed\n");
47727d4f2c6SRoger Quadros 		return -EADDRNOTAVAIL;
4781e7fe1a9SKeshava Munegowda 	}
4791e7fe1a9SKeshava Munegowda 
4801e7fe1a9SKeshava Munegowda 	spin_lock_init(&omap->lock);
4811e7fe1a9SKeshava Munegowda 
4829d9c6ae7SRoger Quadros 	omap->pdata = pdata;
4831e7fe1a9SKeshava Munegowda 
4841e7fe1a9SKeshava Munegowda 	pm_runtime_enable(dev);
4851e7fe1a9SKeshava Munegowda 
486d7eaf866SRoger Quadros 	platform_set_drvdata(pdev, omap);
487d7eaf866SRoger Quadros 	pm_runtime_get_sync(dev);
488d7eaf866SRoger Quadros 
489d7eaf866SRoger Quadros 	omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
490d7eaf866SRoger Quadros 
491d7eaf866SRoger Quadros 	/* we need to call runtime suspend before we update omap->nports
492d7eaf866SRoger Quadros 	 * to prevent unbalanced clk_disable()
493d7eaf866SRoger Quadros 	 */
494d7eaf866SRoger Quadros 	pm_runtime_put_sync(dev);
495d7eaf866SRoger Quadros 
496d7eaf866SRoger Quadros 	switch (omap->usbhs_rev) {
497d7eaf866SRoger Quadros 	case OMAP_USBHS_REV1:
498d7eaf866SRoger Quadros 		omap->nports = 3;
499d7eaf866SRoger Quadros 		break;
500d7eaf866SRoger Quadros 	case OMAP_USBHS_REV2:
501d7eaf866SRoger Quadros 		omap->nports = 2;
502d7eaf866SRoger Quadros 		break;
503d7eaf866SRoger Quadros 	default:
504d7eaf866SRoger Quadros 		omap->nports = OMAP3_HS_USB_PORTS;
505d7eaf866SRoger Quadros 		dev_dbg(dev,
506d7eaf866SRoger Quadros 		  "USB HOST Rev : 0x%d not recognized, assuming %d ports\n",
507d7eaf866SRoger Quadros 		   omap->usbhs_rev, omap->nports);
508d7eaf866SRoger Quadros 		break;
509d7eaf866SRoger Quadros 	}
510d7eaf866SRoger Quadros 
511d7eaf866SRoger Quadros 	for (i = 0; i < omap->nports; i++)
5121e7fe1a9SKeshava Munegowda 		if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
5131e7fe1a9SKeshava Munegowda 			is_ehci_hsic_mode(i)) {
5141e7fe1a9SKeshava Munegowda 			omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
5151e7fe1a9SKeshava Munegowda 			if (IS_ERR(omap->ehci_logic_fck)) {
5161e7fe1a9SKeshava Munegowda 				ret = PTR_ERR(omap->ehci_logic_fck);
5171e7fe1a9SKeshava Munegowda 				dev_warn(dev, "ehci_logic_fck failed:%d\n",
5181e7fe1a9SKeshava Munegowda 					 ret);
5191e7fe1a9SKeshava Munegowda 			}
5201e7fe1a9SKeshava Munegowda 			break;
5211e7fe1a9SKeshava Munegowda 		}
5221e7fe1a9SKeshava Munegowda 
5231e7fe1a9SKeshava Munegowda 	omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
5241e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->utmi_p1_fck)) {
5251e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->utmi_p1_fck);
5261e7fe1a9SKeshava Munegowda 		dev_err(dev, "utmi_p1_gfclk failed error:%d\n",	ret);
5271e7fe1a9SKeshava Munegowda 		goto err_end;
5281e7fe1a9SKeshava Munegowda 	}
5291e7fe1a9SKeshava Munegowda 
5301e7fe1a9SKeshava Munegowda 	omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
5311e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->xclk60mhsp1_ck)) {
5321e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->xclk60mhsp1_ck);
5331e7fe1a9SKeshava Munegowda 		dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
5341e7fe1a9SKeshava Munegowda 		goto err_utmi_p1_fck;
5351e7fe1a9SKeshava Munegowda 	}
5361e7fe1a9SKeshava Munegowda 
5371e7fe1a9SKeshava Munegowda 	omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
5381e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->utmi_p2_fck)) {
5391e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->utmi_p2_fck);
5401e7fe1a9SKeshava Munegowda 		dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
5411e7fe1a9SKeshava Munegowda 		goto err_xclk60mhsp1_ck;
5421e7fe1a9SKeshava Munegowda 	}
5431e7fe1a9SKeshava Munegowda 
5441e7fe1a9SKeshava Munegowda 	omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
5451e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->xclk60mhsp2_ck)) {
5461e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->xclk60mhsp2_ck);
5471e7fe1a9SKeshava Munegowda 		dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
5481e7fe1a9SKeshava Munegowda 		goto err_utmi_p2_fck;
5491e7fe1a9SKeshava Munegowda 	}
5501e7fe1a9SKeshava Munegowda 
5511e7fe1a9SKeshava Munegowda 	omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
5521e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->usbhost_p1_fck)) {
5531e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->usbhost_p1_fck);
5541e7fe1a9SKeshava Munegowda 		dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
5551e7fe1a9SKeshava Munegowda 		goto err_xclk60mhsp2_ck;
5561e7fe1a9SKeshava Munegowda 	}
5571e7fe1a9SKeshava Munegowda 
5581e7fe1a9SKeshava Munegowda 	omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
5591e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->usbhost_p2_fck)) {
5601e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->usbhost_p2_fck);
5611e7fe1a9SKeshava Munegowda 		dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
562760189b3SKeshava Munegowda 		goto err_usbhost_p1_fck;
5631e7fe1a9SKeshava Munegowda 	}
5641e7fe1a9SKeshava Munegowda 
5651e7fe1a9SKeshava Munegowda 	omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
5661e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->init_60m_fclk)) {
5671e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->init_60m_fclk);
5681e7fe1a9SKeshava Munegowda 		dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
569760189b3SKeshava Munegowda 		goto err_usbhost_p2_fck;
5701e7fe1a9SKeshava Munegowda 	}
5711e7fe1a9SKeshava Munegowda 
5721e7fe1a9SKeshava Munegowda 	if (is_ehci_phy_mode(pdata->port_mode[0])) {
5731e7fe1a9SKeshava Munegowda 		/* for OMAP3 , the clk set paretn fails */
5741e7fe1a9SKeshava Munegowda 		ret = clk_set_parent(omap->utmi_p1_fck,
5751e7fe1a9SKeshava Munegowda 					omap->xclk60mhsp1_ck);
5761e7fe1a9SKeshava Munegowda 		if (ret != 0)
5771e7fe1a9SKeshava Munegowda 			dev_err(dev, "xclk60mhsp1_ck set parent"
5781e7fe1a9SKeshava Munegowda 				"failed error:%d\n", ret);
5791e7fe1a9SKeshava Munegowda 	} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
5801e7fe1a9SKeshava Munegowda 		ret = clk_set_parent(omap->utmi_p1_fck,
5811e7fe1a9SKeshava Munegowda 					omap->init_60m_fclk);
5821e7fe1a9SKeshava Munegowda 		if (ret != 0)
5831e7fe1a9SKeshava Munegowda 			dev_err(dev, "init_60m_fclk set parent"
5841e7fe1a9SKeshava Munegowda 				"failed error:%d\n", ret);
5851e7fe1a9SKeshava Munegowda 	}
5861e7fe1a9SKeshava Munegowda 
5871e7fe1a9SKeshava Munegowda 	if (is_ehci_phy_mode(pdata->port_mode[1])) {
5881e7fe1a9SKeshava Munegowda 		ret = clk_set_parent(omap->utmi_p2_fck,
5891e7fe1a9SKeshava Munegowda 					omap->xclk60mhsp2_ck);
5901e7fe1a9SKeshava Munegowda 		if (ret != 0)
5911e7fe1a9SKeshava Munegowda 			dev_err(dev, "xclk60mhsp2_ck set parent"
5921e7fe1a9SKeshava Munegowda 					"failed error:%d\n", ret);
5931e7fe1a9SKeshava Munegowda 	} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
5941e7fe1a9SKeshava Munegowda 		ret = clk_set_parent(omap->utmi_p2_fck,
5951e7fe1a9SKeshava Munegowda 						omap->init_60m_fclk);
5961e7fe1a9SKeshava Munegowda 		if (ret != 0)
5971e7fe1a9SKeshava Munegowda 			dev_err(dev, "init_60m_fclk set parent"
5981e7fe1a9SKeshava Munegowda 				"failed error:%d\n", ret);
5991e7fe1a9SKeshava Munegowda 	}
6001e7fe1a9SKeshava Munegowda 
601f0447a69SGovindraj.R 	omap_usbhs_init(dev);
6021e7fe1a9SKeshava Munegowda 	ret = omap_usbhs_alloc_children(pdev);
6031e7fe1a9SKeshava Munegowda 	if (ret) {
6041e7fe1a9SKeshava Munegowda 		dev_err(dev, "omap_usbhs_alloc_children failed\n");
6051e7fe1a9SKeshava Munegowda 		goto err_alloc;
6061e7fe1a9SKeshava Munegowda 	}
6071e7fe1a9SKeshava Munegowda 
60827d4f2c6SRoger Quadros 	return 0;
6091e7fe1a9SKeshava Munegowda 
6101e7fe1a9SKeshava Munegowda err_alloc:
611c05995c3SRuss Dill 	omap_usbhs_deinit(&pdev->dev);
6121e7fe1a9SKeshava Munegowda 	clk_put(omap->init_60m_fclk);
6131e7fe1a9SKeshava Munegowda 
6141e7fe1a9SKeshava Munegowda err_usbhost_p2_fck:
6151e7fe1a9SKeshava Munegowda 	clk_put(omap->usbhost_p2_fck);
6161e7fe1a9SKeshava Munegowda 
6171e7fe1a9SKeshava Munegowda err_usbhost_p1_fck:
6181e7fe1a9SKeshava Munegowda 	clk_put(omap->usbhost_p1_fck);
6191e7fe1a9SKeshava Munegowda 
6201e7fe1a9SKeshava Munegowda err_xclk60mhsp2_ck:
6211e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp2_ck);
6221e7fe1a9SKeshava Munegowda 
6231e7fe1a9SKeshava Munegowda err_utmi_p2_fck:
6241e7fe1a9SKeshava Munegowda 	clk_put(omap->utmi_p2_fck);
6251e7fe1a9SKeshava Munegowda 
6261e7fe1a9SKeshava Munegowda err_xclk60mhsp1_ck:
6271e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp1_ck);
6281e7fe1a9SKeshava Munegowda 
6291e7fe1a9SKeshava Munegowda err_utmi_p1_fck:
6301e7fe1a9SKeshava Munegowda 	clk_put(omap->utmi_p1_fck);
6311e7fe1a9SKeshava Munegowda 
6321e7fe1a9SKeshava Munegowda err_end:
6331e7fe1a9SKeshava Munegowda 	clk_put(omap->ehci_logic_fck);
6341e7fe1a9SKeshava Munegowda 	pm_runtime_disable(dev);
6351e7fe1a9SKeshava Munegowda 
6361e7fe1a9SKeshava Munegowda 	return ret;
6371e7fe1a9SKeshava Munegowda }
6381e7fe1a9SKeshava Munegowda 
6391e7fe1a9SKeshava Munegowda /**
6401e7fe1a9SKeshava Munegowda  * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
6411e7fe1a9SKeshava Munegowda  * @pdev: USB Host Controller being removed
6421e7fe1a9SKeshava Munegowda  *
6431e7fe1a9SKeshava Munegowda  * Reverses the effect of usbhs_omap_probe().
6441e7fe1a9SKeshava Munegowda  */
6454740f73fSBill Pemberton static int usbhs_omap_remove(struct platform_device *pdev)
6461e7fe1a9SKeshava Munegowda {
6471e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
6481e7fe1a9SKeshava Munegowda 
649c05995c3SRuss Dill 	omap_usbhs_deinit(&pdev->dev);
6501e7fe1a9SKeshava Munegowda 	clk_put(omap->init_60m_fclk);
6511e7fe1a9SKeshava Munegowda 	clk_put(omap->usbhost_p2_fck);
6521e7fe1a9SKeshava Munegowda 	clk_put(omap->usbhost_p1_fck);
6531e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp2_ck);
6541e7fe1a9SKeshava Munegowda 	clk_put(omap->utmi_p2_fck);
6551e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp1_ck);
6561e7fe1a9SKeshava Munegowda 	clk_put(omap->utmi_p1_fck);
6571e7fe1a9SKeshava Munegowda 	clk_put(omap->ehci_logic_fck);
6581e7fe1a9SKeshava Munegowda 	pm_runtime_disable(&pdev->dev);
6591e7fe1a9SKeshava Munegowda 
6601e7fe1a9SKeshava Munegowda 	return 0;
6611e7fe1a9SKeshava Munegowda }
6621e7fe1a9SKeshava Munegowda 
6631e7fe1a9SKeshava Munegowda static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
6641e7fe1a9SKeshava Munegowda 	.runtime_suspend	= usbhs_runtime_suspend,
6651e7fe1a9SKeshava Munegowda 	.runtime_resume		= usbhs_runtime_resume,
6661e7fe1a9SKeshava Munegowda };
66717cdd29dSKeshava Munegowda 
66817cdd29dSKeshava Munegowda static struct platform_driver usbhs_omap_driver = {
66917cdd29dSKeshava Munegowda 	.driver = {
67017cdd29dSKeshava Munegowda 		.name		= (char *)usbhs_driver_name,
67117cdd29dSKeshava Munegowda 		.owner		= THIS_MODULE,
6721e7fe1a9SKeshava Munegowda 		.pm		= &usbhsomap_dev_pm_ops,
67317cdd29dSKeshava Munegowda 	},
67417cdd29dSKeshava Munegowda 	.remove		= __exit_p(usbhs_omap_remove),
67517cdd29dSKeshava Munegowda };
67617cdd29dSKeshava Munegowda 
67717cdd29dSKeshava Munegowda MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
67817cdd29dSKeshava Munegowda MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
67917cdd29dSKeshava Munegowda MODULE_LICENSE("GPL v2");
68017cdd29dSKeshava Munegowda MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
68117cdd29dSKeshava Munegowda 
68217cdd29dSKeshava Munegowda static int __init omap_usbhs_drvinit(void)
68317cdd29dSKeshava Munegowda {
68417cdd29dSKeshava Munegowda 	return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe);
68517cdd29dSKeshava Munegowda }
68617cdd29dSKeshava Munegowda 
68717cdd29dSKeshava Munegowda /*
68817cdd29dSKeshava Munegowda  * init before ehci and ohci drivers;
68917cdd29dSKeshava Munegowda  * The usbhs core driver should be initialized much before
69017cdd29dSKeshava Munegowda  * the omap ehci and ohci probe functions are called.
6914dc2ccebSKeshava Munegowda  * This usbhs core driver should be initialized after
6924dc2ccebSKeshava Munegowda  * usb tll driver
69317cdd29dSKeshava Munegowda  */
6944dc2ccebSKeshava Munegowda fs_initcall_sync(omap_usbhs_drvinit);
69517cdd29dSKeshava Munegowda 
69617cdd29dSKeshava Munegowda static void __exit omap_usbhs_drvexit(void)
69717cdd29dSKeshava Munegowda {
69817cdd29dSKeshava Munegowda 	platform_driver_unregister(&usbhs_omap_driver);
69917cdd29dSKeshava Munegowda }
70017cdd29dSKeshava Munegowda module_exit(omap_usbhs_drvexit);
701