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