xref: /openbmc/linux/drivers/mfd/omap-usb-host.c (revision 340c64ea)
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;
9506ba7dc7SRoger Quadros 	struct clk			**utmi_clk;
96340c64eaSRoger Quadros 	struct clk			**hsic60m_clk;
97340c64eaSRoger Quadros 	struct clk			**hsic480m_clk;
98d7eaf866SRoger Quadros 
9917cdd29dSKeshava Munegowda 	struct clk			*xclk60mhsp1_ck;
10017cdd29dSKeshava Munegowda 	struct clk			*xclk60mhsp2_ck;
10106ba7dc7SRoger Quadros 	struct clk			*utmi_p1_gfclk;
10206ba7dc7SRoger Quadros 	struct clk			*utmi_p2_gfclk;
10317cdd29dSKeshava Munegowda 	struct clk			*init_60m_fclk;
1041e7fe1a9SKeshava Munegowda 	struct clk			*ehci_logic_fck;
10517cdd29dSKeshava Munegowda 
10617cdd29dSKeshava Munegowda 	void __iomem			*uhh_base;
10717cdd29dSKeshava Munegowda 
1089d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata;
10917cdd29dSKeshava Munegowda 
11017cdd29dSKeshava Munegowda 	u32				usbhs_rev;
11117cdd29dSKeshava Munegowda 	spinlock_t			lock;
11217cdd29dSKeshava Munegowda };
11317cdd29dSKeshava Munegowda /*-------------------------------------------------------------------------*/
11417cdd29dSKeshava Munegowda 
11517cdd29dSKeshava Munegowda const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
116cbb8c220SGovindraj.R static u64 usbhs_dmamask = DMA_BIT_MASK(32);
11717cdd29dSKeshava Munegowda 
11817cdd29dSKeshava Munegowda /*-------------------------------------------------------------------------*/
11917cdd29dSKeshava Munegowda 
12017cdd29dSKeshava Munegowda static inline void usbhs_write(void __iomem *base, u32 reg, u32 val)
12117cdd29dSKeshava Munegowda {
12217cdd29dSKeshava Munegowda 	__raw_writel(val, base + reg);
12317cdd29dSKeshava Munegowda }
12417cdd29dSKeshava Munegowda 
12517cdd29dSKeshava Munegowda static inline u32 usbhs_read(void __iomem *base, u32 reg)
12617cdd29dSKeshava Munegowda {
12717cdd29dSKeshava Munegowda 	return __raw_readl(base + reg);
12817cdd29dSKeshava Munegowda }
12917cdd29dSKeshava Munegowda 
13017cdd29dSKeshava Munegowda static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val)
13117cdd29dSKeshava Munegowda {
13217cdd29dSKeshava Munegowda 	__raw_writeb(val, base + reg);
13317cdd29dSKeshava Munegowda }
13417cdd29dSKeshava Munegowda 
13517cdd29dSKeshava Munegowda static inline u8 usbhs_readb(void __iomem *base, u8 reg)
13617cdd29dSKeshava Munegowda {
13717cdd29dSKeshava Munegowda 	return __raw_readb(base + reg);
13817cdd29dSKeshava Munegowda }
13917cdd29dSKeshava Munegowda 
14017cdd29dSKeshava Munegowda /*-------------------------------------------------------------------------*/
14117cdd29dSKeshava Munegowda 
14217cdd29dSKeshava Munegowda static struct platform_device *omap_usbhs_alloc_child(const char *name,
14317cdd29dSKeshava Munegowda 			struct resource	*res, int num_resources, void *pdata,
14417cdd29dSKeshava Munegowda 			size_t pdata_size, struct device *dev)
14517cdd29dSKeshava Munegowda {
14617cdd29dSKeshava Munegowda 	struct platform_device	*child;
14717cdd29dSKeshava Munegowda 	int			ret;
14817cdd29dSKeshava Munegowda 
14917cdd29dSKeshava Munegowda 	child = platform_device_alloc(name, 0);
15017cdd29dSKeshava Munegowda 
15117cdd29dSKeshava Munegowda 	if (!child) {
15217cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_alloc %s failed\n", name);
15317cdd29dSKeshava Munegowda 		goto err_end;
15417cdd29dSKeshava Munegowda 	}
15517cdd29dSKeshava Munegowda 
15617cdd29dSKeshava Munegowda 	ret = platform_device_add_resources(child, res, num_resources);
15717cdd29dSKeshava Munegowda 	if (ret) {
15817cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_add_resources failed\n");
15917cdd29dSKeshava Munegowda 		goto err_alloc;
16017cdd29dSKeshava Munegowda 	}
16117cdd29dSKeshava Munegowda 
16217cdd29dSKeshava Munegowda 	ret = platform_device_add_data(child, pdata, pdata_size);
16317cdd29dSKeshava Munegowda 	if (ret) {
16417cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_add_data failed\n");
16517cdd29dSKeshava Munegowda 		goto err_alloc;
16617cdd29dSKeshava Munegowda 	}
16717cdd29dSKeshava Munegowda 
16817cdd29dSKeshava Munegowda 	child->dev.dma_mask		= &usbhs_dmamask;
169cbb8c220SGovindraj.R 	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
17017cdd29dSKeshava Munegowda 	child->dev.parent		= dev;
17117cdd29dSKeshava Munegowda 
17217cdd29dSKeshava Munegowda 	ret = platform_device_add(child);
17317cdd29dSKeshava Munegowda 	if (ret) {
17417cdd29dSKeshava Munegowda 		dev_err(dev, "platform_device_add failed\n");
17517cdd29dSKeshava Munegowda 		goto err_alloc;
17617cdd29dSKeshava Munegowda 	}
17717cdd29dSKeshava Munegowda 
17817cdd29dSKeshava Munegowda 	return child;
17917cdd29dSKeshava Munegowda 
18017cdd29dSKeshava Munegowda err_alloc:
18117cdd29dSKeshava Munegowda 	platform_device_put(child);
18217cdd29dSKeshava Munegowda 
18317cdd29dSKeshava Munegowda err_end:
18417cdd29dSKeshava Munegowda 	return NULL;
18517cdd29dSKeshava Munegowda }
18617cdd29dSKeshava Munegowda 
18717cdd29dSKeshava Munegowda static int omap_usbhs_alloc_children(struct platform_device *pdev)
18817cdd29dSKeshava Munegowda {
18917cdd29dSKeshava Munegowda 	struct device				*dev = &pdev->dev;
1909d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data		*pdata = dev->platform_data;
19117cdd29dSKeshava Munegowda 	struct platform_device			*ehci;
19217cdd29dSKeshava Munegowda 	struct platform_device			*ohci;
19317cdd29dSKeshava Munegowda 	struct resource				*res;
19417cdd29dSKeshava Munegowda 	struct resource				resources[2];
19517cdd29dSKeshava Munegowda 	int					ret;
19617cdd29dSKeshava Munegowda 
19717cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
19817cdd29dSKeshava Munegowda 	if (!res) {
19917cdd29dSKeshava Munegowda 		dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
20017cdd29dSKeshava Munegowda 		ret = -ENODEV;
20117cdd29dSKeshava Munegowda 		goto err_end;
20217cdd29dSKeshava Munegowda 	}
20317cdd29dSKeshava Munegowda 	resources[0] = *res;
20417cdd29dSKeshava Munegowda 
20517cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq");
20617cdd29dSKeshava Munegowda 	if (!res) {
20717cdd29dSKeshava Munegowda 		dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n");
20817cdd29dSKeshava Munegowda 		ret = -ENODEV;
20917cdd29dSKeshava Munegowda 		goto err_end;
21017cdd29dSKeshava Munegowda 	}
21117cdd29dSKeshava Munegowda 	resources[1] = *res;
21217cdd29dSKeshava Munegowda 
2139d9c6ae7SRoger Quadros 	ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
2149d9c6ae7SRoger Quadros 		sizeof(*pdata), dev);
21517cdd29dSKeshava Munegowda 
21617cdd29dSKeshava Munegowda 	if (!ehci) {
21717cdd29dSKeshava Munegowda 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
218d910774fSAxel Lin 		ret = -ENOMEM;
21917cdd29dSKeshava Munegowda 		goto err_end;
22017cdd29dSKeshava Munegowda 	}
22117cdd29dSKeshava Munegowda 
22217cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci");
22317cdd29dSKeshava Munegowda 	if (!res) {
22417cdd29dSKeshava Munegowda 		dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n");
22517cdd29dSKeshava Munegowda 		ret = -ENODEV;
22617cdd29dSKeshava Munegowda 		goto err_ehci;
22717cdd29dSKeshava Munegowda 	}
22817cdd29dSKeshava Munegowda 	resources[0] = *res;
22917cdd29dSKeshava Munegowda 
23017cdd29dSKeshava Munegowda 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq");
23117cdd29dSKeshava Munegowda 	if (!res) {
23217cdd29dSKeshava Munegowda 		dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n");
23317cdd29dSKeshava Munegowda 		ret = -ENODEV;
23417cdd29dSKeshava Munegowda 		goto err_ehci;
23517cdd29dSKeshava Munegowda 	}
23617cdd29dSKeshava Munegowda 	resources[1] = *res;
23717cdd29dSKeshava Munegowda 
2389d9c6ae7SRoger Quadros 	ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
2399d9c6ae7SRoger Quadros 		sizeof(*pdata), dev);
24017cdd29dSKeshava Munegowda 	if (!ohci) {
24117cdd29dSKeshava Munegowda 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
242d910774fSAxel Lin 		ret = -ENOMEM;
24317cdd29dSKeshava Munegowda 		goto err_ehci;
24417cdd29dSKeshava Munegowda 	}
24517cdd29dSKeshava Munegowda 
24617cdd29dSKeshava Munegowda 	return 0;
24717cdd29dSKeshava Munegowda 
24817cdd29dSKeshava Munegowda err_ehci:
249d910774fSAxel Lin 	platform_device_unregister(ehci);
25017cdd29dSKeshava Munegowda 
25117cdd29dSKeshava Munegowda err_end:
25217cdd29dSKeshava Munegowda 	return ret;
25317cdd29dSKeshava Munegowda }
25417cdd29dSKeshava Munegowda 
25517cdd29dSKeshava Munegowda static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
25617cdd29dSKeshava Munegowda {
25717cdd29dSKeshava Munegowda 	switch (pmode) {
25817cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
25917cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
26017cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
26117cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
26217cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
26317cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
26417cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
26517cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
26617cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
26717cdd29dSKeshava Munegowda 	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
26817cdd29dSKeshava Munegowda 		return true;
26917cdd29dSKeshava Munegowda 
27017cdd29dSKeshava Munegowda 	default:
27117cdd29dSKeshava Munegowda 		return false;
27217cdd29dSKeshava Munegowda 	}
27317cdd29dSKeshava Munegowda }
27417cdd29dSKeshava Munegowda 
2751e7fe1a9SKeshava Munegowda static int usbhs_runtime_resume(struct device *dev)
27617cdd29dSKeshava Munegowda {
27717cdd29dSKeshava Munegowda 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
2789d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
2791e7fe1a9SKeshava Munegowda 	unsigned long			flags;
28006ba7dc7SRoger Quadros 	int i, r;
28117cdd29dSKeshava Munegowda 
2821e7fe1a9SKeshava Munegowda 	dev_dbg(dev, "usbhs_runtime_resume\n");
2831e7fe1a9SKeshava Munegowda 
2844dc2ccebSKeshava Munegowda 	omap_tll_enable();
28517cdd29dSKeshava Munegowda 	spin_lock_irqsave(&omap->lock, flags);
28617cdd29dSKeshava Munegowda 
28706ba7dc7SRoger Quadros 	if (!IS_ERR(omap->ehci_logic_fck))
2881e7fe1a9SKeshava Munegowda 		clk_enable(omap->ehci_logic_fck);
2891e7fe1a9SKeshava Munegowda 
29006ba7dc7SRoger Quadros 	for (i = 0; i < omap->nports; i++) {
291340c64eaSRoger Quadros 		switch (pdata->port_mode[i]) {
292340c64eaSRoger Quadros 		case OMAP_EHCI_PORT_MODE_HSIC:
293340c64eaSRoger Quadros 			if (!IS_ERR(omap->hsic60m_clk[i])) {
294340c64eaSRoger Quadros 				r = clk_enable(omap->hsic60m_clk[i]);
295340c64eaSRoger Quadros 				if (r) {
296340c64eaSRoger Quadros 					dev_err(dev,
297340c64eaSRoger Quadros 					 "Can't enable port %d hsic60m clk:%d\n",
298340c64eaSRoger Quadros 					 i, r);
299340c64eaSRoger Quadros 				}
300340c64eaSRoger Quadros 			}
301760189b3SKeshava Munegowda 
302340c64eaSRoger Quadros 			if (!IS_ERR(omap->hsic480m_clk[i])) {
303340c64eaSRoger Quadros 				r = clk_enable(omap->hsic480m_clk[i]);
304340c64eaSRoger Quadros 				if (r) {
305340c64eaSRoger Quadros 					dev_err(dev,
306340c64eaSRoger Quadros 					 "Can't enable port %d hsic480m clk:%d\n",
307340c64eaSRoger Quadros 					 i, r);
308340c64eaSRoger Quadros 				}
309340c64eaSRoger Quadros 			}
310340c64eaSRoger Quadros 		/* Fall through as HSIC mode needs utmi_clk */
311340c64eaSRoger Quadros 
312340c64eaSRoger Quadros 		case OMAP_EHCI_PORT_MODE_TLL:
313340c64eaSRoger Quadros 			if (!IS_ERR(omap->utmi_clk[i])) {
31406ba7dc7SRoger Quadros 				r = clk_enable(omap->utmi_clk[i]);
315340c64eaSRoger Quadros 				if (r) {
316340c64eaSRoger Quadros 					dev_err(dev,
317340c64eaSRoger Quadros 					 "Can't enable port %d clk : %d\n",
318340c64eaSRoger Quadros 					 i, r);
319340c64eaSRoger Quadros 				}
320340c64eaSRoger Quadros 			}
321340c64eaSRoger Quadros 			break;
322340c64eaSRoger Quadros 		default:
323340c64eaSRoger Quadros 			break;
324340c64eaSRoger Quadros 		}
32506ba7dc7SRoger Quadros 	}
3261e7fe1a9SKeshava Munegowda 
3271e7fe1a9SKeshava Munegowda 	spin_unlock_irqrestore(&omap->lock, flags);
3281e7fe1a9SKeshava Munegowda 
3291e7fe1a9SKeshava Munegowda 	return 0;
3301e7fe1a9SKeshava Munegowda }
3311e7fe1a9SKeshava Munegowda 
3321e7fe1a9SKeshava Munegowda static int usbhs_runtime_suspend(struct device *dev)
3331e7fe1a9SKeshava Munegowda {
3341e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
3359d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
3361e7fe1a9SKeshava Munegowda 	unsigned long			flags;
33706ba7dc7SRoger Quadros 	int i;
3381e7fe1a9SKeshava Munegowda 
3391e7fe1a9SKeshava Munegowda 	dev_dbg(dev, "usbhs_runtime_suspend\n");
3401e7fe1a9SKeshava Munegowda 
3411e7fe1a9SKeshava Munegowda 	spin_lock_irqsave(&omap->lock, flags);
3421e7fe1a9SKeshava Munegowda 
34306ba7dc7SRoger Quadros 	for (i = 0; i < omap->nports; i++) {
344340c64eaSRoger Quadros 		switch (pdata->port_mode[i]) {
345340c64eaSRoger Quadros 		case OMAP_EHCI_PORT_MODE_HSIC:
346340c64eaSRoger Quadros 			if (!IS_ERR(omap->hsic60m_clk[i]))
347340c64eaSRoger Quadros 				clk_disable(omap->hsic60m_clk[i]);
348340c64eaSRoger Quadros 
349340c64eaSRoger Quadros 			if (!IS_ERR(omap->hsic480m_clk[i]))
350340c64eaSRoger Quadros 				clk_disable(omap->hsic480m_clk[i]);
351340c64eaSRoger Quadros 		/* Fall through as utmi_clks were used in HSIC mode */
352340c64eaSRoger Quadros 
353340c64eaSRoger Quadros 		case OMAP_EHCI_PORT_MODE_TLL:
354340c64eaSRoger Quadros 			if (!IS_ERR(omap->utmi_clk[i]))
35506ba7dc7SRoger Quadros 				clk_disable(omap->utmi_clk[i]);
356340c64eaSRoger Quadros 			break;
357340c64eaSRoger Quadros 		default:
358340c64eaSRoger Quadros 			break;
359340c64eaSRoger Quadros 		}
36006ba7dc7SRoger Quadros 	}
361760189b3SKeshava Munegowda 
36206ba7dc7SRoger Quadros 	if (!IS_ERR(omap->ehci_logic_fck))
3631e7fe1a9SKeshava Munegowda 		clk_disable(omap->ehci_logic_fck);
3641e7fe1a9SKeshava Munegowda 
3651e7fe1a9SKeshava Munegowda 	spin_unlock_irqrestore(&omap->lock, flags);
3664dc2ccebSKeshava Munegowda 	omap_tll_disable();
3671e7fe1a9SKeshava Munegowda 
3681e7fe1a9SKeshava Munegowda 	return 0;
3691e7fe1a9SKeshava Munegowda }
3701e7fe1a9SKeshava Munegowda 
3711e7fe1a9SKeshava Munegowda static void omap_usbhs_init(struct device *dev)
3721e7fe1a9SKeshava Munegowda {
3731e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
3749d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
3751e7fe1a9SKeshava Munegowda 	unsigned long			flags;
3761e7fe1a9SKeshava Munegowda 	unsigned			reg;
3771e7fe1a9SKeshava Munegowda 
3781e7fe1a9SKeshava Munegowda 	dev_dbg(dev, "starting TI HSUSB Controller\n");
3791e7fe1a9SKeshava Munegowda 
3809d9c6ae7SRoger Quadros 	if (pdata->phy_reset) {
3819d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
3829d9c6ae7SRoger Quadros 			gpio_request_one(pdata->reset_gpio_port[0],
383c05995c3SRuss Dill 					 GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
384c05995c3SRuss Dill 
3859d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
3869d9c6ae7SRoger Quadros 			gpio_request_one(pdata->reset_gpio_port[1],
387c05995c3SRuss Dill 					 GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
388c05995c3SRuss Dill 
389c05995c3SRuss Dill 		/* Hold the PHY in RESET for enough time till DIR is high */
390c05995c3SRuss Dill 		udelay(10);
391c05995c3SRuss Dill 	}
392c05995c3SRuss Dill 
393760189b3SKeshava Munegowda 	pm_runtime_get_sync(dev);
394c05995c3SRuss Dill 	spin_lock_irqsave(&omap->lock, flags);
39517cdd29dSKeshava Munegowda 
39617cdd29dSKeshava Munegowda 	reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
39717cdd29dSKeshava Munegowda 	/* setup ULPI bypass and burst configurations */
39817cdd29dSKeshava Munegowda 	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
39917cdd29dSKeshava Munegowda 			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
40017cdd29dSKeshava Munegowda 			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
40117cdd29dSKeshava Munegowda 	reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
40217cdd29dSKeshava Munegowda 	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
40317cdd29dSKeshava Munegowda 
40417cdd29dSKeshava Munegowda 	if (is_omap_usbhs_rev1(omap)) {
40517cdd29dSKeshava Munegowda 		if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED)
40617cdd29dSKeshava Munegowda 			reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
40717cdd29dSKeshava Munegowda 		if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED)
40817cdd29dSKeshava Munegowda 			reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
40917cdd29dSKeshava Munegowda 		if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED)
41017cdd29dSKeshava Munegowda 			reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
41117cdd29dSKeshava Munegowda 
41217cdd29dSKeshava Munegowda 		/* Bypass the TLL module for PHY mode operation */
41363b68901SRoger Quadros 		if (pdata->single_ulpi_bypass) {
41417cdd29dSKeshava Munegowda 			dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
41517cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[0]) ||
41617cdd29dSKeshava Munegowda 				is_ehci_phy_mode(pdata->port_mode[1]) ||
41717cdd29dSKeshava Munegowda 					is_ehci_phy_mode(pdata->port_mode[2]))
41817cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
41917cdd29dSKeshava Munegowda 			else
42017cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
42117cdd29dSKeshava Munegowda 		} else {
42217cdd29dSKeshava Munegowda 			dev_dbg(dev, "OMAP3 ES version > ES2.1\n");
42317cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[0]))
42417cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
42517cdd29dSKeshava Munegowda 			else
42617cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
42717cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[1]))
42817cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
42917cdd29dSKeshava Munegowda 			else
43017cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
43117cdd29dSKeshava Munegowda 			if (is_ehci_phy_mode(pdata->port_mode[2]))
43217cdd29dSKeshava Munegowda 				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
43317cdd29dSKeshava Munegowda 			else
43417cdd29dSKeshava Munegowda 				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
43517cdd29dSKeshava Munegowda 		}
43617cdd29dSKeshava Munegowda 	} else if (is_omap_usbhs_rev2(omap)) {
43717cdd29dSKeshava Munegowda 		/* Clear port mode fields for PHY mode*/
43817cdd29dSKeshava Munegowda 		reg &= ~OMAP4_P1_MODE_CLEAR;
43917cdd29dSKeshava Munegowda 		reg &= ~OMAP4_P2_MODE_CLEAR;
44017cdd29dSKeshava Munegowda 
44117cdd29dSKeshava Munegowda 		if (is_ehci_tll_mode(pdata->port_mode[0]) ||
44217cdd29dSKeshava Munegowda 			(is_ohci_port(pdata->port_mode[0])))
44317cdd29dSKeshava Munegowda 			reg |= OMAP4_P1_MODE_TLL;
44417cdd29dSKeshava Munegowda 		else if (is_ehci_hsic_mode(pdata->port_mode[0]))
44517cdd29dSKeshava Munegowda 			reg |= OMAP4_P1_MODE_HSIC;
44617cdd29dSKeshava Munegowda 
44717cdd29dSKeshava Munegowda 		if (is_ehci_tll_mode(pdata->port_mode[1]) ||
44817cdd29dSKeshava Munegowda 			(is_ohci_port(pdata->port_mode[1])))
44917cdd29dSKeshava Munegowda 			reg |= OMAP4_P2_MODE_TLL;
45017cdd29dSKeshava Munegowda 		else if (is_ehci_hsic_mode(pdata->port_mode[1]))
45117cdd29dSKeshava Munegowda 			reg |= OMAP4_P2_MODE_HSIC;
45217cdd29dSKeshava Munegowda 	}
45317cdd29dSKeshava Munegowda 
45417cdd29dSKeshava Munegowda 	usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
45517cdd29dSKeshava Munegowda 	dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
45617cdd29dSKeshava Munegowda 
457d11536e4SAxel Lin 	spin_unlock_irqrestore(&omap->lock, flags);
458c05995c3SRuss Dill 
459760189b3SKeshava Munegowda 	pm_runtime_put_sync(dev);
4609d9c6ae7SRoger Quadros 	if (pdata->phy_reset) {
461c05995c3SRuss Dill 		/* Hold the PHY in RESET for enough time till
462c05995c3SRuss Dill 		 * PHY is settled and ready
463c05995c3SRuss Dill 		 */
464c05995c3SRuss Dill 		udelay(10);
465c05995c3SRuss Dill 
4669d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
467c05995c3SRuss Dill 			gpio_set_value_cansleep
4689d9c6ae7SRoger Quadros 				(pdata->reset_gpio_port[0], 1);
469c05995c3SRuss Dill 
4709d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
471c05995c3SRuss Dill 			gpio_set_value_cansleep
4729d9c6ae7SRoger Quadros 				(pdata->reset_gpio_port[1], 1);
473c05995c3SRuss Dill 	}
47417cdd29dSKeshava Munegowda }
4758f2df014SKeshava Munegowda 
476c05995c3SRuss Dill static void omap_usbhs_deinit(struct device *dev)
477c05995c3SRuss Dill {
478c05995c3SRuss Dill 	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
4799d9c6ae7SRoger Quadros 	struct usbhs_omap_platform_data	*pdata = omap->pdata;
480c05995c3SRuss Dill 
4819d9c6ae7SRoger Quadros 	if (pdata->phy_reset) {
4829d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
4839d9c6ae7SRoger Quadros 			gpio_free(pdata->reset_gpio_port[0]);
484c05995c3SRuss Dill 
4859d9c6ae7SRoger Quadros 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
4869d9c6ae7SRoger Quadros 			gpio_free(pdata->reset_gpio_port[1]);
487c05995c3SRuss Dill 	}
488c05995c3SRuss Dill }
489c05995c3SRuss Dill 
4901e7fe1a9SKeshava Munegowda 
4911e7fe1a9SKeshava Munegowda /**
4921e7fe1a9SKeshava Munegowda  * usbhs_omap_probe - initialize TI-based HCDs
4931e7fe1a9SKeshava Munegowda  *
4941e7fe1a9SKeshava Munegowda  * Allocates basic resources for this USB host controller.
4951e7fe1a9SKeshava Munegowda  */
496f791be49SBill Pemberton static int usbhs_omap_probe(struct platform_device *pdev)
49717cdd29dSKeshava Munegowda {
4981e7fe1a9SKeshava Munegowda 	struct device			*dev =  &pdev->dev;
4991e7fe1a9SKeshava Munegowda 	struct usbhs_omap_platform_data	*pdata = dev->platform_data;
5001e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap		*omap;
5011e7fe1a9SKeshava Munegowda 	struct resource			*res;
5021e7fe1a9SKeshava Munegowda 	int				ret = 0;
5031e7fe1a9SKeshava Munegowda 	int				i;
50406ba7dc7SRoger Quadros 	bool				need_logic_fck;
50517cdd29dSKeshava Munegowda 
5061e7fe1a9SKeshava Munegowda 	if (!pdata) {
5071e7fe1a9SKeshava Munegowda 		dev_err(dev, "Missing platform data\n");
50827d4f2c6SRoger Quadros 		return -ENODEV;
50917cdd29dSKeshava Munegowda 	}
5101e7fe1a9SKeshava Munegowda 
51127d4f2c6SRoger Quadros 	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
5121e7fe1a9SKeshava Munegowda 	if (!omap) {
5131e7fe1a9SKeshava Munegowda 		dev_err(dev, "Memory allocation failed\n");
51427d4f2c6SRoger Quadros 		return -ENOMEM;
51527d4f2c6SRoger Quadros 	}
51627d4f2c6SRoger Quadros 
51727d4f2c6SRoger Quadros 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
51827d4f2c6SRoger Quadros 	omap->uhh_base = devm_request_and_ioremap(dev, res);
51927d4f2c6SRoger Quadros 	if (!omap->uhh_base) {
52027d4f2c6SRoger Quadros 		dev_err(dev, "Resource request/ioremap failed\n");
52127d4f2c6SRoger Quadros 		return -EADDRNOTAVAIL;
5221e7fe1a9SKeshava Munegowda 	}
5231e7fe1a9SKeshava Munegowda 
5241e7fe1a9SKeshava Munegowda 	spin_lock_init(&omap->lock);
5251e7fe1a9SKeshava Munegowda 
5269d9c6ae7SRoger Quadros 	omap->pdata = pdata;
5271e7fe1a9SKeshava Munegowda 
5281e7fe1a9SKeshava Munegowda 	pm_runtime_enable(dev);
5291e7fe1a9SKeshava Munegowda 
530d7eaf866SRoger Quadros 	platform_set_drvdata(pdev, omap);
531d7eaf866SRoger Quadros 	pm_runtime_get_sync(dev);
532d7eaf866SRoger Quadros 
533d7eaf866SRoger Quadros 	omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
534d7eaf866SRoger Quadros 
535d7eaf866SRoger Quadros 	/* we need to call runtime suspend before we update omap->nports
536d7eaf866SRoger Quadros 	 * to prevent unbalanced clk_disable()
537d7eaf866SRoger Quadros 	 */
538d7eaf866SRoger Quadros 	pm_runtime_put_sync(dev);
539d7eaf866SRoger Quadros 
540ccac71a7SRoger Quadros 	/*
541ccac71a7SRoger Quadros 	 * If platform data contains nports then use that
542ccac71a7SRoger Quadros 	 * else make out number of ports from USBHS revision
543ccac71a7SRoger Quadros 	 */
544ccac71a7SRoger Quadros 	if (pdata->nports) {
545ccac71a7SRoger Quadros 		omap->nports = pdata->nports;
546ccac71a7SRoger Quadros 	} else {
547d7eaf866SRoger Quadros 		switch (omap->usbhs_rev) {
548d7eaf866SRoger Quadros 		case OMAP_USBHS_REV1:
549d7eaf866SRoger Quadros 			omap->nports = 3;
550d7eaf866SRoger Quadros 			break;
551d7eaf866SRoger Quadros 		case OMAP_USBHS_REV2:
552d7eaf866SRoger Quadros 			omap->nports = 2;
553d7eaf866SRoger Quadros 			break;
554d7eaf866SRoger Quadros 		default:
555d7eaf866SRoger Quadros 			omap->nports = OMAP3_HS_USB_PORTS;
556d7eaf866SRoger Quadros 			dev_dbg(dev,
557d7eaf866SRoger Quadros 			 "USB HOST Rev:0x%d not recognized, assuming %d ports\n",
558d7eaf866SRoger Quadros 			 omap->usbhs_rev, omap->nports);
559d7eaf866SRoger Quadros 			break;
560d7eaf866SRoger Quadros 		}
561ccac71a7SRoger Quadros 	}
562d7eaf866SRoger Quadros 
56306ba7dc7SRoger Quadros 	i = sizeof(struct clk *) * omap->nports;
56406ba7dc7SRoger Quadros 	omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
565340c64eaSRoger Quadros 	omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
566340c64eaSRoger Quadros 	omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
567340c64eaSRoger Quadros 
568340c64eaSRoger Quadros 	if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
56906ba7dc7SRoger Quadros 		dev_err(dev, "Memory allocation failed\n");
57006ba7dc7SRoger Quadros 		ret = -ENOMEM;
57106ba7dc7SRoger Quadros 		goto err_mem;
57206ba7dc7SRoger Quadros 	}
57306ba7dc7SRoger Quadros 
57406ba7dc7SRoger Quadros 	need_logic_fck = false;
57506ba7dc7SRoger Quadros 	for (i = 0; i < omap->nports; i++) {
5761e7fe1a9SKeshava Munegowda 		if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
57706ba7dc7SRoger Quadros 			is_ehci_hsic_mode(i))
57806ba7dc7SRoger Quadros 				need_logic_fck |= true;
57906ba7dc7SRoger Quadros 	}
58006ba7dc7SRoger Quadros 
58106ba7dc7SRoger Quadros 	omap->ehci_logic_fck = ERR_PTR(-EINVAL);
58206ba7dc7SRoger Quadros 	if (need_logic_fck) {
5831e7fe1a9SKeshava Munegowda 		omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
5841e7fe1a9SKeshava Munegowda 		if (IS_ERR(omap->ehci_logic_fck)) {
5851e7fe1a9SKeshava Munegowda 			ret = PTR_ERR(omap->ehci_logic_fck);
58606ba7dc7SRoger Quadros 			dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret);
5871e7fe1a9SKeshava Munegowda 		}
5881e7fe1a9SKeshava Munegowda 	}
5891e7fe1a9SKeshava Munegowda 
59006ba7dc7SRoger Quadros 	omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
59106ba7dc7SRoger Quadros 	if (IS_ERR(omap->utmi_p1_gfclk)) {
59206ba7dc7SRoger Quadros 		ret = PTR_ERR(omap->utmi_p1_gfclk);
5931e7fe1a9SKeshava Munegowda 		dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
59406ba7dc7SRoger Quadros 		goto err_p1_gfclk;
59506ba7dc7SRoger Quadros 	}
59606ba7dc7SRoger Quadros 
59706ba7dc7SRoger Quadros 	omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
59806ba7dc7SRoger Quadros 	if (IS_ERR(omap->utmi_p2_gfclk)) {
59906ba7dc7SRoger Quadros 		ret = PTR_ERR(omap->utmi_p2_gfclk);
60006ba7dc7SRoger Quadros 		dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
60106ba7dc7SRoger Quadros 		goto err_p2_gfclk;
6021e7fe1a9SKeshava Munegowda 	}
6031e7fe1a9SKeshava Munegowda 
6041e7fe1a9SKeshava Munegowda 	omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
6051e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->xclk60mhsp1_ck)) {
6061e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->xclk60mhsp1_ck);
6071e7fe1a9SKeshava Munegowda 		dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
60806ba7dc7SRoger Quadros 		goto err_xclk60mhsp1;
6091e7fe1a9SKeshava Munegowda 	}
6101e7fe1a9SKeshava Munegowda 
6111e7fe1a9SKeshava Munegowda 	omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
6121e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->xclk60mhsp2_ck)) {
6131e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->xclk60mhsp2_ck);
6141e7fe1a9SKeshava Munegowda 		dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
61506ba7dc7SRoger Quadros 		goto err_xclk60mhsp2;
6161e7fe1a9SKeshava Munegowda 	}
6171e7fe1a9SKeshava Munegowda 
6181e7fe1a9SKeshava Munegowda 	omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
6191e7fe1a9SKeshava Munegowda 	if (IS_ERR(omap->init_60m_fclk)) {
6201e7fe1a9SKeshava Munegowda 		ret = PTR_ERR(omap->init_60m_fclk);
6211e7fe1a9SKeshava Munegowda 		dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
62206ba7dc7SRoger Quadros 		goto err_init60m;
62306ba7dc7SRoger Quadros 	}
62406ba7dc7SRoger Quadros 
62506ba7dc7SRoger Quadros 	for (i = 0; i < omap->nports; i++) {
626340c64eaSRoger Quadros 		char clkname[30];
62706ba7dc7SRoger Quadros 
62806ba7dc7SRoger Quadros 		/* clock names are indexed from 1*/
62906ba7dc7SRoger Quadros 		snprintf(clkname, sizeof(clkname),
63006ba7dc7SRoger Quadros 				"usb_host_hs_utmi_p%d_clk", i + 1);
63106ba7dc7SRoger Quadros 
63206ba7dc7SRoger Quadros 		/* If a clock is not found we won't bail out as not all
63306ba7dc7SRoger Quadros 		 * platforms have all clocks and we can function without
63406ba7dc7SRoger Quadros 		 * them
63506ba7dc7SRoger Quadros 		 */
63606ba7dc7SRoger Quadros 		omap->utmi_clk[i] = clk_get(dev, clkname);
63706ba7dc7SRoger Quadros 		if (IS_ERR(omap->utmi_clk[i]))
63806ba7dc7SRoger Quadros 			dev_dbg(dev, "Failed to get clock : %s : %ld\n",
63906ba7dc7SRoger Quadros 				clkname, PTR_ERR(omap->utmi_clk[i]));
640340c64eaSRoger Quadros 
641340c64eaSRoger Quadros 		snprintf(clkname, sizeof(clkname),
642340c64eaSRoger Quadros 				"usb_host_hs_hsic480m_p%d_clk", i + 1);
643340c64eaSRoger Quadros 		omap->hsic480m_clk[i] = clk_get(dev, clkname);
644340c64eaSRoger Quadros 		if (IS_ERR(omap->hsic480m_clk[i]))
645340c64eaSRoger Quadros 			dev_dbg(dev, "Failed to get clock : %s : %ld\n",
646340c64eaSRoger Quadros 				clkname, PTR_ERR(omap->hsic480m_clk[i]));
647340c64eaSRoger Quadros 
648340c64eaSRoger Quadros 		snprintf(clkname, sizeof(clkname),
649340c64eaSRoger Quadros 				"usb_host_hs_hsic60m_p%d_clk", i + 1);
650340c64eaSRoger Quadros 		omap->hsic60m_clk[i] = clk_get(dev, clkname);
651340c64eaSRoger Quadros 		if (IS_ERR(omap->hsic60m_clk[i]))
652340c64eaSRoger Quadros 			dev_dbg(dev, "Failed to get clock : %s : %ld\n",
653340c64eaSRoger Quadros 				clkname, PTR_ERR(omap->hsic60m_clk[i]));
6541e7fe1a9SKeshava Munegowda 	}
6551e7fe1a9SKeshava Munegowda 
6561e7fe1a9SKeshava Munegowda 	if (is_ehci_phy_mode(pdata->port_mode[0])) {
6571e7fe1a9SKeshava Munegowda 		/* for OMAP3 , the clk set paretn fails */
65806ba7dc7SRoger Quadros 		ret = clk_set_parent(omap->utmi_p1_gfclk,
6591e7fe1a9SKeshava Munegowda 					omap->xclk60mhsp1_ck);
6601e7fe1a9SKeshava Munegowda 		if (ret != 0)
6611e7fe1a9SKeshava Munegowda 			dev_err(dev, "xclk60mhsp1_ck set parent"
6621e7fe1a9SKeshava Munegowda 				"failed error:%d\n", ret);
6631e7fe1a9SKeshava Munegowda 	} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
66406ba7dc7SRoger Quadros 		ret = clk_set_parent(omap->utmi_p1_gfclk,
6651e7fe1a9SKeshava Munegowda 					omap->init_60m_fclk);
6661e7fe1a9SKeshava Munegowda 		if (ret != 0)
6671e7fe1a9SKeshava Munegowda 			dev_err(dev, "init_60m_fclk set parent"
6681e7fe1a9SKeshava Munegowda 				"failed error:%d\n", ret);
6691e7fe1a9SKeshava Munegowda 	}
6701e7fe1a9SKeshava Munegowda 
6711e7fe1a9SKeshava Munegowda 	if (is_ehci_phy_mode(pdata->port_mode[1])) {
67206ba7dc7SRoger Quadros 		ret = clk_set_parent(omap->utmi_p2_gfclk,
6731e7fe1a9SKeshava Munegowda 					omap->xclk60mhsp2_ck);
6741e7fe1a9SKeshava Munegowda 		if (ret != 0)
6751e7fe1a9SKeshava Munegowda 			dev_err(dev, "xclk60mhsp2_ck set parent"
6761e7fe1a9SKeshava Munegowda 					"failed error:%d\n", ret);
6771e7fe1a9SKeshava Munegowda 	} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
67806ba7dc7SRoger Quadros 		ret = clk_set_parent(omap->utmi_p2_gfclk,
6791e7fe1a9SKeshava Munegowda 						omap->init_60m_fclk);
6801e7fe1a9SKeshava Munegowda 		if (ret != 0)
6811e7fe1a9SKeshava Munegowda 			dev_err(dev, "init_60m_fclk set parent"
6821e7fe1a9SKeshava Munegowda 				"failed error:%d\n", ret);
6831e7fe1a9SKeshava Munegowda 	}
6841e7fe1a9SKeshava Munegowda 
685f0447a69SGovindraj.R 	omap_usbhs_init(dev);
6861e7fe1a9SKeshava Munegowda 	ret = omap_usbhs_alloc_children(pdev);
6871e7fe1a9SKeshava Munegowda 	if (ret) {
6881e7fe1a9SKeshava Munegowda 		dev_err(dev, "omap_usbhs_alloc_children failed\n");
6891e7fe1a9SKeshava Munegowda 		goto err_alloc;
6901e7fe1a9SKeshava Munegowda 	}
6911e7fe1a9SKeshava Munegowda 
69227d4f2c6SRoger Quadros 	return 0;
6931e7fe1a9SKeshava Munegowda 
6941e7fe1a9SKeshava Munegowda err_alloc:
695c05995c3SRuss Dill 	omap_usbhs_deinit(&pdev->dev);
69606ba7dc7SRoger Quadros 
697340c64eaSRoger Quadros 	for (i = 0; i < omap->nports; i++) {
69806ba7dc7SRoger Quadros 		if (!IS_ERR(omap->utmi_clk[i]))
69906ba7dc7SRoger Quadros 			clk_put(omap->utmi_clk[i]);
700340c64eaSRoger Quadros 		if (!IS_ERR(omap->hsic60m_clk[i]))
701340c64eaSRoger Quadros 			clk_put(omap->hsic60m_clk[i]);
702340c64eaSRoger Quadros 		if (!IS_ERR(omap->hsic480m_clk[i]))
703340c64eaSRoger Quadros 			clk_put(omap->hsic480m_clk[i]);
704340c64eaSRoger Quadros 	}
70506ba7dc7SRoger Quadros 
7061e7fe1a9SKeshava Munegowda 	clk_put(omap->init_60m_fclk);
7071e7fe1a9SKeshava Munegowda 
70806ba7dc7SRoger Quadros err_init60m:
7091e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp2_ck);
7101e7fe1a9SKeshava Munegowda 
71106ba7dc7SRoger Quadros err_xclk60mhsp2:
7121e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp1_ck);
7131e7fe1a9SKeshava Munegowda 
71406ba7dc7SRoger Quadros err_xclk60mhsp1:
71506ba7dc7SRoger Quadros 	clk_put(omap->utmi_p2_gfclk);
7161e7fe1a9SKeshava Munegowda 
71706ba7dc7SRoger Quadros err_p2_gfclk:
71806ba7dc7SRoger Quadros 	clk_put(omap->utmi_p1_gfclk);
71906ba7dc7SRoger Quadros 
72006ba7dc7SRoger Quadros err_p1_gfclk:
72106ba7dc7SRoger Quadros 	if (!IS_ERR(omap->ehci_logic_fck))
7221e7fe1a9SKeshava Munegowda 		clk_put(omap->ehci_logic_fck);
72306ba7dc7SRoger Quadros 
72406ba7dc7SRoger Quadros err_mem:
7251e7fe1a9SKeshava Munegowda 	pm_runtime_disable(dev);
7261e7fe1a9SKeshava Munegowda 
7271e7fe1a9SKeshava Munegowda 	return ret;
7281e7fe1a9SKeshava Munegowda }
7291e7fe1a9SKeshava Munegowda 
7301e7fe1a9SKeshava Munegowda /**
7311e7fe1a9SKeshava Munegowda  * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
7321e7fe1a9SKeshava Munegowda  * @pdev: USB Host Controller being removed
7331e7fe1a9SKeshava Munegowda  *
7341e7fe1a9SKeshava Munegowda  * Reverses the effect of usbhs_omap_probe().
7351e7fe1a9SKeshava Munegowda  */
7364740f73fSBill Pemberton static int usbhs_omap_remove(struct platform_device *pdev)
7371e7fe1a9SKeshava Munegowda {
7381e7fe1a9SKeshava Munegowda 	struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
73906ba7dc7SRoger Quadros 	int i;
7401e7fe1a9SKeshava Munegowda 
741c05995c3SRuss Dill 	omap_usbhs_deinit(&pdev->dev);
74206ba7dc7SRoger Quadros 
743340c64eaSRoger Quadros 	for (i = 0; i < omap->nports; i++) {
74406ba7dc7SRoger Quadros 		if (!IS_ERR(omap->utmi_clk[i]))
74506ba7dc7SRoger Quadros 			clk_put(omap->utmi_clk[i]);
746340c64eaSRoger Quadros 		if (!IS_ERR(omap->hsic60m_clk[i]))
747340c64eaSRoger Quadros 			clk_put(omap->hsic60m_clk[i]);
748340c64eaSRoger Quadros 		if (!IS_ERR(omap->hsic480m_clk[i]))
749340c64eaSRoger Quadros 			clk_put(omap->hsic480m_clk[i]);
750340c64eaSRoger Quadros 	}
75106ba7dc7SRoger Quadros 
7521e7fe1a9SKeshava Munegowda 	clk_put(omap->init_60m_fclk);
75306ba7dc7SRoger Quadros 	clk_put(omap->utmi_p1_gfclk);
75406ba7dc7SRoger Quadros 	clk_put(omap->utmi_p2_gfclk);
7551e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp2_ck);
7561e7fe1a9SKeshava Munegowda 	clk_put(omap->xclk60mhsp1_ck);
75706ba7dc7SRoger Quadros 
75806ba7dc7SRoger Quadros 	if (!IS_ERR(omap->ehci_logic_fck))
7591e7fe1a9SKeshava Munegowda 		clk_put(omap->ehci_logic_fck);
76006ba7dc7SRoger Quadros 
7611e7fe1a9SKeshava Munegowda 	pm_runtime_disable(&pdev->dev);
7621e7fe1a9SKeshava Munegowda 
7631e7fe1a9SKeshava Munegowda 	return 0;
7641e7fe1a9SKeshava Munegowda }
7651e7fe1a9SKeshava Munegowda 
7661e7fe1a9SKeshava Munegowda static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
7671e7fe1a9SKeshava Munegowda 	.runtime_suspend	= usbhs_runtime_suspend,
7681e7fe1a9SKeshava Munegowda 	.runtime_resume		= usbhs_runtime_resume,
7691e7fe1a9SKeshava Munegowda };
77017cdd29dSKeshava Munegowda 
77117cdd29dSKeshava Munegowda static struct platform_driver usbhs_omap_driver = {
77217cdd29dSKeshava Munegowda 	.driver = {
77317cdd29dSKeshava Munegowda 		.name		= (char *)usbhs_driver_name,
77417cdd29dSKeshava Munegowda 		.owner		= THIS_MODULE,
7751e7fe1a9SKeshava Munegowda 		.pm		= &usbhsomap_dev_pm_ops,
77617cdd29dSKeshava Munegowda 	},
77717cdd29dSKeshava Munegowda 	.remove		= __exit_p(usbhs_omap_remove),
77817cdd29dSKeshava Munegowda };
77917cdd29dSKeshava Munegowda 
78017cdd29dSKeshava Munegowda MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
78117cdd29dSKeshava Munegowda MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
78217cdd29dSKeshava Munegowda MODULE_LICENSE("GPL v2");
78317cdd29dSKeshava Munegowda MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
78417cdd29dSKeshava Munegowda 
78517cdd29dSKeshava Munegowda static int __init omap_usbhs_drvinit(void)
78617cdd29dSKeshava Munegowda {
78717cdd29dSKeshava Munegowda 	return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe);
78817cdd29dSKeshava Munegowda }
78917cdd29dSKeshava Munegowda 
79017cdd29dSKeshava Munegowda /*
79117cdd29dSKeshava Munegowda  * init before ehci and ohci drivers;
79217cdd29dSKeshava Munegowda  * The usbhs core driver should be initialized much before
79317cdd29dSKeshava Munegowda  * the omap ehci and ohci probe functions are called.
7944dc2ccebSKeshava Munegowda  * This usbhs core driver should be initialized after
7954dc2ccebSKeshava Munegowda  * usb tll driver
79617cdd29dSKeshava Munegowda  */
7974dc2ccebSKeshava Munegowda fs_initcall_sync(omap_usbhs_drvinit);
79817cdd29dSKeshava Munegowda 
79917cdd29dSKeshava Munegowda static void __exit omap_usbhs_drvexit(void)
80017cdd29dSKeshava Munegowda {
80117cdd29dSKeshava Munegowda 	platform_driver_unregister(&usbhs_omap_driver);
80217cdd29dSKeshava Munegowda }
80317cdd29dSKeshava Munegowda module_exit(omap_usbhs_drvexit);
804