116fa3dc7SKeshava Munegowda /** 216fa3dc7SKeshava Munegowda * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI 316fa3dc7SKeshava Munegowda * 416fa3dc7SKeshava Munegowda * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com 516fa3dc7SKeshava Munegowda * Author: Keshava Munegowda <keshava_mgowda@ti.com> 616fa3dc7SKeshava Munegowda * 716fa3dc7SKeshava Munegowda * This program is free software: you can redistribute it and/or modify 816fa3dc7SKeshava Munegowda * it under the terms of the GNU General Public License version 2 of 916fa3dc7SKeshava Munegowda * the License as published by the Free Software Foundation. 1016fa3dc7SKeshava Munegowda * 1116fa3dc7SKeshava Munegowda * This program is distributed in the hope that it will be useful, 1216fa3dc7SKeshava Munegowda * but WITHOUT ANY WARRANTY; without even the implied warranty of 1316fa3dc7SKeshava Munegowda * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1416fa3dc7SKeshava Munegowda * GNU General Public License for more details. 1516fa3dc7SKeshava Munegowda * 1616fa3dc7SKeshava Munegowda * You should have received a copy of the GNU General Public License 1716fa3dc7SKeshava Munegowda * along with this program. If not, see <http://www.gnu.org/licenses/>. 1816fa3dc7SKeshava Munegowda */ 1916fa3dc7SKeshava Munegowda #include <linux/kernel.h> 2016fa3dc7SKeshava Munegowda #include <linux/module.h> 2116fa3dc7SKeshava Munegowda #include <linux/types.h> 2216fa3dc7SKeshava Munegowda #include <linux/slab.h> 2316fa3dc7SKeshava Munegowda #include <linux/spinlock.h> 2416fa3dc7SKeshava Munegowda #include <linux/platform_device.h> 2516fa3dc7SKeshava Munegowda #include <linux/clk.h> 2616fa3dc7SKeshava Munegowda #include <linux/io.h> 2716fa3dc7SKeshava Munegowda #include <linux/err.h> 2816fa3dc7SKeshava Munegowda #include <linux/pm_runtime.h> 29e8c4a7acSFelipe Balbi #include <linux/platform_data/usb-omap.h> 3016fa3dc7SKeshava Munegowda 3116fa3dc7SKeshava Munegowda #define USBTLL_DRIVER_NAME "usbhs_tll" 3216fa3dc7SKeshava Munegowda 3316fa3dc7SKeshava Munegowda /* TLL Register Set */ 3416fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REVISION (0x00) 3516fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG (0x10) 3616fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) 3716fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) 3816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) 3916fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) 4016fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) 4116fa3dc7SKeshava Munegowda 4216fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSSTATUS (0x14) 4316fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) 4416fa3dc7SKeshava Munegowda 4516fa3dc7SKeshava Munegowda #define OMAP_USBTLL_IRQSTATUS (0x18) 4616fa3dc7SKeshava Munegowda #define OMAP_USBTLL_IRQENABLE (0x1C) 4716fa3dc7SKeshava Munegowda 4816fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF (0x30) 4916fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) 5016fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) 5116fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) 5216fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) 5316fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) 5416fa3dc7SKeshava Munegowda 5516fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) 5616fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 5716fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) 5816fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) 5916fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) 6016fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) 6116fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) 6216fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) 6316fa3dc7SKeshava Munegowda 6416fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 6516fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 6616fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 6716fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 6816fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 6916fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 7016fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 7116fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 7216fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA 7316fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB 7416fa3dc7SKeshava Munegowda 7516fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) 7616fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) 7716fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) 7816fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) 7916fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) 8016fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) 8116fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) 8216fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) 8316fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) 8416fa3dc7SKeshava Munegowda 8516fa3dc7SKeshava Munegowda #define OMAP_REV2_TLL_CHANNEL_COUNT 2 8616fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_COUNT 3 8716fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) 8816fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) 8916fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) 9016fa3dc7SKeshava Munegowda 9116fa3dc7SKeshava Munegowda /* Values of USBTLL_REVISION - Note: these are not given in the TRM */ 9216fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ 9316fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ 9416fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ 9516fa3dc7SKeshava Munegowda 9616fa3dc7SKeshava Munegowda #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) 9716fa3dc7SKeshava Munegowda 9832a51f2aSRoger Quadros /* only PHY and UNUSED modes don't need TLL */ 9932a51f2aSRoger Quadros #define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\ 10032a51f2aSRoger Quadros (x) != OMAP_EHCI_PORT_MODE_PHY) 10132a51f2aSRoger Quadros 10216fa3dc7SKeshava Munegowda struct usbtll_omap { 1037e0ff103SRoger Quadros int nch; /* num. of channels */ 1049d9c6ae7SRoger Quadros struct usbhs_omap_platform_data *pdata; 1050bde3e9fSRoger Quadros struct clk **ch_clk; 10616fa3dc7SKeshava Munegowda }; 10716fa3dc7SKeshava Munegowda 10816fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 10916fa3dc7SKeshava Munegowda 1107ed86191SRoger Quadros static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; 1117ed86191SRoger Quadros static struct device *tll_dev; 11266751446SRoger Quadros static DEFINE_SPINLOCK(tll_lock); /* serialize access to tll_dev */ 11316fa3dc7SKeshava Munegowda 11416fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 11516fa3dc7SKeshava Munegowda 11616fa3dc7SKeshava Munegowda static inline void usbtll_write(void __iomem *base, u32 reg, u32 val) 11716fa3dc7SKeshava Munegowda { 11816fa3dc7SKeshava Munegowda __raw_writel(val, base + reg); 11916fa3dc7SKeshava Munegowda } 12016fa3dc7SKeshava Munegowda 12116fa3dc7SKeshava Munegowda static inline u32 usbtll_read(void __iomem *base, u32 reg) 12216fa3dc7SKeshava Munegowda { 12316fa3dc7SKeshava Munegowda return __raw_readl(base + reg); 12416fa3dc7SKeshava Munegowda } 12516fa3dc7SKeshava Munegowda 12616fa3dc7SKeshava Munegowda static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) 12716fa3dc7SKeshava Munegowda { 12816fa3dc7SKeshava Munegowda __raw_writeb(val, base + reg); 12916fa3dc7SKeshava Munegowda } 13016fa3dc7SKeshava Munegowda 13116fa3dc7SKeshava Munegowda static inline u8 usbtll_readb(void __iomem *base, u8 reg) 13216fa3dc7SKeshava Munegowda { 13316fa3dc7SKeshava Munegowda return __raw_readb(base + reg); 13416fa3dc7SKeshava Munegowda } 13516fa3dc7SKeshava Munegowda 13616fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 13716fa3dc7SKeshava Munegowda 13816fa3dc7SKeshava Munegowda static bool is_ohci_port(enum usbhs_omap_port_mode pmode) 13916fa3dc7SKeshava Munegowda { 14016fa3dc7SKeshava Munegowda switch (pmode) { 14116fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: 14216fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: 14316fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: 14416fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: 14516fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: 14616fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: 14716fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: 14816fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: 14916fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: 15016fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: 15116fa3dc7SKeshava Munegowda return true; 15216fa3dc7SKeshava Munegowda 15316fa3dc7SKeshava Munegowda default: 15416fa3dc7SKeshava Munegowda return false; 15516fa3dc7SKeshava Munegowda } 15616fa3dc7SKeshava Munegowda } 15716fa3dc7SKeshava Munegowda 15816fa3dc7SKeshava Munegowda /* 15916fa3dc7SKeshava Munegowda * convert the port-mode enum to a value we can use in the FSLSMODE 16016fa3dc7SKeshava Munegowda * field of USBTLL_CHANNEL_CONF 16116fa3dc7SKeshava Munegowda */ 16216fa3dc7SKeshava Munegowda static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) 16316fa3dc7SKeshava Munegowda { 16416fa3dc7SKeshava Munegowda switch (mode) { 16516fa3dc7SKeshava Munegowda case OMAP_USBHS_PORT_MODE_UNUSED: 16616fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: 16716fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; 16816fa3dc7SKeshava Munegowda 16916fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: 17016fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; 17116fa3dc7SKeshava Munegowda 17216fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: 17316fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_3PIN_PHY; 17416fa3dc7SKeshava Munegowda 17516fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: 17616fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_4PIN_PHY; 17716fa3dc7SKeshava Munegowda 17816fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: 17916fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; 18016fa3dc7SKeshava Munegowda 18116fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: 18216fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; 18316fa3dc7SKeshava Munegowda 18416fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: 18516fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_3PIN_TLL; 18616fa3dc7SKeshava Munegowda 18716fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: 18816fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_4PIN_TLL; 18916fa3dc7SKeshava Munegowda 19016fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: 19116fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; 19216fa3dc7SKeshava Munegowda 19316fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: 19416fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; 19516fa3dc7SKeshava Munegowda default: 19616fa3dc7SKeshava Munegowda pr_warn("Invalid port mode, using default\n"); 19716fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; 19816fa3dc7SKeshava Munegowda } 19916fa3dc7SKeshava Munegowda } 20016fa3dc7SKeshava Munegowda 20116fa3dc7SKeshava Munegowda /** 20216fa3dc7SKeshava Munegowda * usbtll_omap_probe - initialize TI-based HCDs 20316fa3dc7SKeshava Munegowda * 20416fa3dc7SKeshava Munegowda * Allocates basic resources for this USB host controller. 20516fa3dc7SKeshava Munegowda */ 206f791be49SBill Pemberton static int usbtll_omap_probe(struct platform_device *pdev) 20716fa3dc7SKeshava Munegowda { 20816fa3dc7SKeshava Munegowda struct device *dev = &pdev->dev; 2099d9c6ae7SRoger Quadros struct usbhs_omap_platform_data *pdata = dev->platform_data; 21016fa3dc7SKeshava Munegowda void __iomem *base; 21116fa3dc7SKeshava Munegowda struct resource *res; 21216fa3dc7SKeshava Munegowda struct usbtll_omap *tll; 21316fa3dc7SKeshava Munegowda unsigned reg; 21416fa3dc7SKeshava Munegowda int ret = 0; 2157e0ff103SRoger Quadros int i, ver; 21632a51f2aSRoger Quadros bool needs_tll; 21716fa3dc7SKeshava Munegowda 21816fa3dc7SKeshava Munegowda dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); 21916fa3dc7SKeshava Munegowda 2201a7a8d70SRoger Quadros tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL); 22116fa3dc7SKeshava Munegowda if (!tll) { 22216fa3dc7SKeshava Munegowda dev_err(dev, "Memory allocation failed\n"); 2231a7a8d70SRoger Quadros return -ENOMEM; 22416fa3dc7SKeshava Munegowda } 22516fa3dc7SKeshava Munegowda 2268bdbd154SRoger Quadros if (!pdata) { 2278bdbd154SRoger Quadros dev_err(dev, "Platform data missing\n"); 2288bdbd154SRoger Quadros return -ENODEV; 2298bdbd154SRoger Quadros } 2308bdbd154SRoger Quadros 2319d9c6ae7SRoger Quadros tll->pdata = pdata; 23216fa3dc7SKeshava Munegowda 23316fa3dc7SKeshava Munegowda res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2341a7a8d70SRoger Quadros base = devm_request_and_ioremap(dev, res); 23516fa3dc7SKeshava Munegowda if (!base) { 2361a7a8d70SRoger Quadros ret = -EADDRNOTAVAIL; 2371a7a8d70SRoger Quadros dev_err(dev, "Resource request/ioremap failed:%d\n", ret); 2380bde3e9fSRoger Quadros return ret; 23916fa3dc7SKeshava Munegowda } 24016fa3dc7SKeshava Munegowda 24116fa3dc7SKeshava Munegowda platform_set_drvdata(pdev, tll); 24216fa3dc7SKeshava Munegowda pm_runtime_enable(dev); 24316fa3dc7SKeshava Munegowda pm_runtime_get_sync(dev); 24416fa3dc7SKeshava Munegowda 24516fa3dc7SKeshava Munegowda ver = usbtll_read(base, OMAP_USBTLL_REVISION); 24616fa3dc7SKeshava Munegowda switch (ver) { 24716fa3dc7SKeshava Munegowda case OMAP_USBTLL_REV1: 2487e0ff103SRoger Quadros tll->nch = OMAP_TLL_CHANNEL_COUNT; 24916fa3dc7SKeshava Munegowda break; 2507e0ff103SRoger Quadros case OMAP_USBTLL_REV2: 25116fa3dc7SKeshava Munegowda case OMAP_USBTLL_REV3: 2527e0ff103SRoger Quadros tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT; 25316fa3dc7SKeshava Munegowda break; 25416fa3dc7SKeshava Munegowda default: 2557e0ff103SRoger Quadros tll->nch = OMAP_TLL_CHANNEL_COUNT; 2567e0ff103SRoger Quadros dev_dbg(dev, 2577e0ff103SRoger Quadros "USB TLL Rev : 0x%x not recognized, assuming %d channels\n", 2587e0ff103SRoger Quadros ver, tll->nch); 2597e0ff103SRoger Quadros break; 26016fa3dc7SKeshava Munegowda } 26116fa3dc7SKeshava Munegowda 2620bde3e9fSRoger Quadros tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]), 2630bde3e9fSRoger Quadros GFP_KERNEL); 2640bde3e9fSRoger Quadros if (!tll->ch_clk) { 2650bde3e9fSRoger Quadros ret = -ENOMEM; 2660bde3e9fSRoger Quadros dev_err(dev, "Couldn't allocate memory for channel clocks\n"); 2670bde3e9fSRoger Quadros goto err_clk_alloc; 2680bde3e9fSRoger Quadros } 2690bde3e9fSRoger Quadros 2700bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 2710bde3e9fSRoger Quadros char clkname[] = "usb_tll_hs_usb_chx_clk"; 2720bde3e9fSRoger Quadros 2730bde3e9fSRoger Quadros snprintf(clkname, sizeof(clkname), 2740bde3e9fSRoger Quadros "usb_tll_hs_usb_ch%d_clk", i); 2750bde3e9fSRoger Quadros tll->ch_clk[i] = clk_get(dev, clkname); 2760bde3e9fSRoger Quadros 2770bde3e9fSRoger Quadros if (IS_ERR(tll->ch_clk[i])) 2780bde3e9fSRoger Quadros dev_dbg(dev, "can't get clock : %s\n", clkname); 2790bde3e9fSRoger Quadros } 2800bde3e9fSRoger Quadros 28132a51f2aSRoger Quadros needs_tll = false; 28232a51f2aSRoger Quadros for (i = 0; i < tll->nch; i++) 28332a51f2aSRoger Quadros needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); 28432a51f2aSRoger Quadros 28532a51f2aSRoger Quadros if (needs_tll) { 28616fa3dc7SKeshava Munegowda 28716fa3dc7SKeshava Munegowda /* Program Common TLL register */ 28816fa3dc7SKeshava Munegowda reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); 28916fa3dc7SKeshava Munegowda reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON 29016fa3dc7SKeshava Munegowda | OMAP_TLL_SHARED_CONF_USB_DIVRATION); 29116fa3dc7SKeshava Munegowda reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; 29216fa3dc7SKeshava Munegowda reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; 29316fa3dc7SKeshava Munegowda 29416fa3dc7SKeshava Munegowda usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); 29516fa3dc7SKeshava Munegowda 29616fa3dc7SKeshava Munegowda /* Enable channels now */ 2977e0ff103SRoger Quadros for (i = 0; i < tll->nch; i++) { 29816fa3dc7SKeshava Munegowda reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); 29916fa3dc7SKeshava Munegowda 30016fa3dc7SKeshava Munegowda if (is_ohci_port(pdata->port_mode[i])) { 30116fa3dc7SKeshava Munegowda reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) 30216fa3dc7SKeshava Munegowda << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; 30316fa3dc7SKeshava Munegowda reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; 30416fa3dc7SKeshava Munegowda } else if (pdata->port_mode[i] == 30516fa3dc7SKeshava Munegowda OMAP_EHCI_PORT_MODE_TLL) { 30616fa3dc7SKeshava Munegowda /* 30716fa3dc7SKeshava Munegowda * Disable AutoIdle, BitStuffing 30816fa3dc7SKeshava Munegowda * and use SDR Mode 30916fa3dc7SKeshava Munegowda */ 31016fa3dc7SKeshava Munegowda reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE 31116fa3dc7SKeshava Munegowda | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF 31216fa3dc7SKeshava Munegowda | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); 31316fa3dc7SKeshava Munegowda } else { 31416fa3dc7SKeshava Munegowda continue; 31516fa3dc7SKeshava Munegowda } 31616fa3dc7SKeshava Munegowda reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; 31716fa3dc7SKeshava Munegowda usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg); 31816fa3dc7SKeshava Munegowda 31916fa3dc7SKeshava Munegowda usbtll_writeb(base, 32016fa3dc7SKeshava Munegowda OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 32116fa3dc7SKeshava Munegowda 0xbe); 32216fa3dc7SKeshava Munegowda } 32316fa3dc7SKeshava Munegowda } 32416fa3dc7SKeshava Munegowda 32516fa3dc7SKeshava Munegowda pm_runtime_put_sync(dev); 3267ed86191SRoger Quadros /* only after this can omap_tll_enable/disable work */ 32766751446SRoger Quadros spin_lock(&tll_lock); 3287ed86191SRoger Quadros tll_dev = dev; 32966751446SRoger Quadros spin_unlock(&tll_lock); 33016fa3dc7SKeshava Munegowda 3311a7a8d70SRoger Quadros return 0; 3321a7a8d70SRoger Quadros 3330bde3e9fSRoger Quadros err_clk_alloc: 3340bde3e9fSRoger Quadros pm_runtime_put_sync(dev); 3350bde3e9fSRoger Quadros pm_runtime_disable(dev); 33616fa3dc7SKeshava Munegowda 33716fa3dc7SKeshava Munegowda return ret; 33816fa3dc7SKeshava Munegowda } 33916fa3dc7SKeshava Munegowda 34016fa3dc7SKeshava Munegowda /** 34116fa3dc7SKeshava Munegowda * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs 34216fa3dc7SKeshava Munegowda * @pdev: USB Host Controller being removed 34316fa3dc7SKeshava Munegowda * 34416fa3dc7SKeshava Munegowda * Reverses the effect of usbtll_omap_probe(). 34516fa3dc7SKeshava Munegowda */ 3464740f73fSBill Pemberton static int usbtll_omap_remove(struct platform_device *pdev) 34716fa3dc7SKeshava Munegowda { 34816fa3dc7SKeshava Munegowda struct usbtll_omap *tll = platform_get_drvdata(pdev); 3490bde3e9fSRoger Quadros int i; 35016fa3dc7SKeshava Munegowda 35166751446SRoger Quadros spin_lock(&tll_lock); 3527ed86191SRoger Quadros tll_dev = NULL; 35366751446SRoger Quadros spin_unlock(&tll_lock); 3547ed86191SRoger Quadros 3550bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) 3560bde3e9fSRoger Quadros if (!IS_ERR(tll->ch_clk[i])) 3570bde3e9fSRoger Quadros clk_put(tll->ch_clk[i]); 3580bde3e9fSRoger Quadros 35916fa3dc7SKeshava Munegowda pm_runtime_disable(&pdev->dev); 36016fa3dc7SKeshava Munegowda return 0; 36116fa3dc7SKeshava Munegowda } 36216fa3dc7SKeshava Munegowda 36316fa3dc7SKeshava Munegowda static int usbtll_runtime_resume(struct device *dev) 36416fa3dc7SKeshava Munegowda { 36516fa3dc7SKeshava Munegowda struct usbtll_omap *tll = dev_get_drvdata(dev); 3669d9c6ae7SRoger Quadros struct usbhs_omap_platform_data *pdata = tll->pdata; 3670bde3e9fSRoger Quadros int i; 36816fa3dc7SKeshava Munegowda 36916fa3dc7SKeshava Munegowda dev_dbg(dev, "usbtll_runtime_resume\n"); 37016fa3dc7SKeshava Munegowda 3710bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 37232a51f2aSRoger Quadros if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { 3730bde3e9fSRoger Quadros int r; 37416fa3dc7SKeshava Munegowda 3750bde3e9fSRoger Quadros if (IS_ERR(tll->ch_clk[i])) 3760bde3e9fSRoger Quadros continue; 3770bde3e9fSRoger Quadros 3780bde3e9fSRoger Quadros r = clk_enable(tll->ch_clk[i]); 3790bde3e9fSRoger Quadros if (r) { 3800bde3e9fSRoger Quadros dev_err(dev, 3810bde3e9fSRoger Quadros "Error enabling ch %d clock: %d\n", i, r); 3820bde3e9fSRoger Quadros } 3830bde3e9fSRoger Quadros } 3840bde3e9fSRoger Quadros } 38516fa3dc7SKeshava Munegowda 38616fa3dc7SKeshava Munegowda return 0; 38716fa3dc7SKeshava Munegowda } 38816fa3dc7SKeshava Munegowda 38916fa3dc7SKeshava Munegowda static int usbtll_runtime_suspend(struct device *dev) 39016fa3dc7SKeshava Munegowda { 39116fa3dc7SKeshava Munegowda struct usbtll_omap *tll = dev_get_drvdata(dev); 3929d9c6ae7SRoger Quadros struct usbhs_omap_platform_data *pdata = tll->pdata; 3930bde3e9fSRoger Quadros int i; 39416fa3dc7SKeshava Munegowda 39516fa3dc7SKeshava Munegowda dev_dbg(dev, "usbtll_runtime_suspend\n"); 39616fa3dc7SKeshava Munegowda 3970bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 39832a51f2aSRoger Quadros if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { 3990bde3e9fSRoger Quadros if (!IS_ERR(tll->ch_clk[i])) 4000bde3e9fSRoger Quadros clk_disable(tll->ch_clk[i]); 4010bde3e9fSRoger Quadros } 4020bde3e9fSRoger Quadros } 40316fa3dc7SKeshava Munegowda 40416fa3dc7SKeshava Munegowda return 0; 40516fa3dc7SKeshava Munegowda } 40616fa3dc7SKeshava Munegowda 40716fa3dc7SKeshava Munegowda static const struct dev_pm_ops usbtllomap_dev_pm_ops = { 40816fa3dc7SKeshava Munegowda SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, 40916fa3dc7SKeshava Munegowda usbtll_runtime_resume, 41016fa3dc7SKeshava Munegowda NULL) 41116fa3dc7SKeshava Munegowda }; 41216fa3dc7SKeshava Munegowda 41316fa3dc7SKeshava Munegowda static struct platform_driver usbtll_omap_driver = { 41416fa3dc7SKeshava Munegowda .driver = { 41516fa3dc7SKeshava Munegowda .name = (char *)usbtll_driver_name, 41616fa3dc7SKeshava Munegowda .owner = THIS_MODULE, 41716fa3dc7SKeshava Munegowda .pm = &usbtllomap_dev_pm_ops, 41816fa3dc7SKeshava Munegowda }, 41916fa3dc7SKeshava Munegowda .probe = usbtll_omap_probe, 42084449216SBill Pemberton .remove = usbtll_omap_remove, 42116fa3dc7SKeshava Munegowda }; 42216fa3dc7SKeshava Munegowda 42316fa3dc7SKeshava Munegowda int omap_tll_enable(void) 42416fa3dc7SKeshava Munegowda { 42566751446SRoger Quadros int ret; 42666751446SRoger Quadros 42766751446SRoger Quadros spin_lock(&tll_lock); 42866751446SRoger Quadros 4297ed86191SRoger Quadros if (!tll_dev) { 4307ed86191SRoger Quadros pr_err("%s: OMAP USB TLL not initialized\n", __func__); 43166751446SRoger Quadros ret = -ENODEV; 43266751446SRoger Quadros } else { 43366751446SRoger Quadros ret = pm_runtime_get_sync(tll_dev); 43416fa3dc7SKeshava Munegowda } 43566751446SRoger Quadros 43666751446SRoger Quadros spin_unlock(&tll_lock); 43766751446SRoger Quadros 43866751446SRoger Quadros return ret; 43916fa3dc7SKeshava Munegowda } 44016fa3dc7SKeshava Munegowda EXPORT_SYMBOL_GPL(omap_tll_enable); 44116fa3dc7SKeshava Munegowda 44216fa3dc7SKeshava Munegowda int omap_tll_disable(void) 44316fa3dc7SKeshava Munegowda { 44466751446SRoger Quadros int ret; 44566751446SRoger Quadros 44666751446SRoger Quadros spin_lock(&tll_lock); 44766751446SRoger Quadros 4487ed86191SRoger Quadros if (!tll_dev) { 4497ed86191SRoger Quadros pr_err("%s: OMAP USB TLL not initialized\n", __func__); 45066751446SRoger Quadros ret = -ENODEV; 45166751446SRoger Quadros } else { 45266751446SRoger Quadros ret = pm_runtime_put_sync(tll_dev); 45316fa3dc7SKeshava Munegowda } 45466751446SRoger Quadros 45566751446SRoger Quadros spin_unlock(&tll_lock); 45666751446SRoger Quadros 45766751446SRoger Quadros return ret; 45816fa3dc7SKeshava Munegowda } 45916fa3dc7SKeshava Munegowda EXPORT_SYMBOL_GPL(omap_tll_disable); 46016fa3dc7SKeshava Munegowda 46116fa3dc7SKeshava Munegowda MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); 46216fa3dc7SKeshava Munegowda MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); 46316fa3dc7SKeshava Munegowda MODULE_LICENSE("GPL v2"); 46416fa3dc7SKeshava Munegowda MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); 46516fa3dc7SKeshava Munegowda 46616fa3dc7SKeshava Munegowda static int __init omap_usbtll_drvinit(void) 46716fa3dc7SKeshava Munegowda { 46816fa3dc7SKeshava Munegowda return platform_driver_register(&usbtll_omap_driver); 46916fa3dc7SKeshava Munegowda } 47016fa3dc7SKeshava Munegowda 47116fa3dc7SKeshava Munegowda /* 47216fa3dc7SKeshava Munegowda * init before usbhs core driver; 47316fa3dc7SKeshava Munegowda * The usbtll driver should be initialized before 47416fa3dc7SKeshava Munegowda * the usbhs core driver probe function is called. 47516fa3dc7SKeshava Munegowda */ 47616fa3dc7SKeshava Munegowda fs_initcall(omap_usbtll_drvinit); 47716fa3dc7SKeshava Munegowda 47816fa3dc7SKeshava Munegowda static void __exit omap_usbtll_drvexit(void) 47916fa3dc7SKeshava Munegowda { 48016fa3dc7SKeshava Munegowda platform_driver_unregister(&usbtll_omap_driver); 48116fa3dc7SKeshava Munegowda } 48216fa3dc7SKeshava Munegowda module_exit(omap_usbtll_drvexit); 483