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