116fa3dc7SKeshava Munegowda /** 216fa3dc7SKeshava Munegowda * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI 316fa3dc7SKeshava Munegowda * 49f4a3eceSRoger Quadros * Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com 516fa3dc7SKeshava Munegowda * Author: Keshava Munegowda <keshava_mgowda@ti.com> 69f4a3eceSRoger Quadros * Author: Roger Quadros <rogerq@ti.com> 716fa3dc7SKeshava Munegowda * 816fa3dc7SKeshava Munegowda * This program is free software: you can redistribute it and/or modify 916fa3dc7SKeshava Munegowda * it under the terms of the GNU General Public License version 2 of 1016fa3dc7SKeshava Munegowda * the License as published by the Free Software Foundation. 1116fa3dc7SKeshava Munegowda * 1216fa3dc7SKeshava Munegowda * This program is distributed in the hope that it will be useful, 1316fa3dc7SKeshava Munegowda * but WITHOUT ANY WARRANTY; without even the implied warranty of 1416fa3dc7SKeshava Munegowda * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1516fa3dc7SKeshava Munegowda * GNU General Public License for more details. 1616fa3dc7SKeshava Munegowda * 1716fa3dc7SKeshava Munegowda * You should have received a copy of the GNU General Public License 1816fa3dc7SKeshava Munegowda * along with this program. If not, see <http://www.gnu.org/licenses/>. 1916fa3dc7SKeshava Munegowda */ 2016fa3dc7SKeshava Munegowda #include <linux/kernel.h> 2116fa3dc7SKeshava Munegowda #include <linux/module.h> 2216fa3dc7SKeshava Munegowda #include <linux/types.h> 2316fa3dc7SKeshava Munegowda #include <linux/slab.h> 2416fa3dc7SKeshava Munegowda #include <linux/spinlock.h> 2516fa3dc7SKeshava Munegowda #include <linux/platform_device.h> 2616fa3dc7SKeshava Munegowda #include <linux/clk.h> 2716fa3dc7SKeshava Munegowda #include <linux/io.h> 2816fa3dc7SKeshava Munegowda #include <linux/err.h> 2916fa3dc7SKeshava Munegowda #include <linux/pm_runtime.h> 30e8c4a7acSFelipe Balbi #include <linux/platform_data/usb-omap.h> 3148130b8fSRoger Quadros #include <linux/of.h> 3216fa3dc7SKeshava Munegowda 3316fa3dc7SKeshava Munegowda #define USBTLL_DRIVER_NAME "usbhs_tll" 3416fa3dc7SKeshava Munegowda 3516fa3dc7SKeshava Munegowda /* TLL Register Set */ 3616fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REVISION (0x00) 3716fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG (0x10) 3816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) 3916fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) 4016fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) 4116fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) 4216fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) 4316fa3dc7SKeshava Munegowda 4416fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSSTATUS (0x14) 4516fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) 4616fa3dc7SKeshava Munegowda 4716fa3dc7SKeshava Munegowda #define OMAP_USBTLL_IRQSTATUS (0x18) 4816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_IRQENABLE (0x1C) 4916fa3dc7SKeshava Munegowda 5016fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF (0x30) 5116fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) 5216fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) 5316fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) 5416fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) 5516fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) 5616fa3dc7SKeshava Munegowda 5716fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) 5816fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 59300c2f8fSRoger Quadros #define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16) 60300c2f8fSRoger Quadros #define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15) 6116fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) 6216fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) 6316fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) 6416fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) 65300c2f8fSRoger Quadros #define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI (2 << 1) 6616fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) 6716fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) 6816fa3dc7SKeshava Munegowda 6916fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 7016fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 7116fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 7216fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 7316fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 7416fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 7516fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 7616fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 7716fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA 7816fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB 7916fa3dc7SKeshava Munegowda 8016fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) 8116fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) 8216fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) 8316fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) 8416fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) 8516fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) 8616fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) 8716fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) 8816fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) 8916fa3dc7SKeshava Munegowda 9016fa3dc7SKeshava Munegowda #define OMAP_REV2_TLL_CHANNEL_COUNT 2 9116fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_COUNT 3 9216fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) 9316fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) 9416fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) 9516fa3dc7SKeshava Munegowda 9616fa3dc7SKeshava Munegowda /* Values of USBTLL_REVISION - Note: these are not given in the TRM */ 9716fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ 9816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ 9916fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ 100300c2f8fSRoger Quadros #define OMAP_USBTLL_REV4 0x00000006 /* OMAP5 */ 10116fa3dc7SKeshava Munegowda 10216fa3dc7SKeshava Munegowda #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) 10316fa3dc7SKeshava Munegowda 10432a51f2aSRoger Quadros /* only PHY and UNUSED modes don't need TLL */ 10532a51f2aSRoger Quadros #define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\ 10632a51f2aSRoger Quadros (x) != OMAP_EHCI_PORT_MODE_PHY) 10732a51f2aSRoger Quadros 10816fa3dc7SKeshava Munegowda struct usbtll_omap { 1097e0ff103SRoger Quadros int nch; /* num. of channels */ 1100bde3e9fSRoger Quadros struct clk **ch_clk; 1119f4a3eceSRoger Quadros void __iomem *base; 11216fa3dc7SKeshava Munegowda }; 11316fa3dc7SKeshava Munegowda 11416fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 11516fa3dc7SKeshava Munegowda 1167ed86191SRoger Quadros static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; 1177ed86191SRoger Quadros static struct device *tll_dev; 11866751446SRoger Quadros static DEFINE_SPINLOCK(tll_lock); /* serialize access to tll_dev */ 11916fa3dc7SKeshava Munegowda 12016fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 12116fa3dc7SKeshava Munegowda 12216fa3dc7SKeshava Munegowda static inline void usbtll_write(void __iomem *base, u32 reg, u32 val) 12316fa3dc7SKeshava Munegowda { 12416fa3dc7SKeshava Munegowda __raw_writel(val, base + reg); 12516fa3dc7SKeshava Munegowda } 12616fa3dc7SKeshava Munegowda 12716fa3dc7SKeshava Munegowda static inline u32 usbtll_read(void __iomem *base, u32 reg) 12816fa3dc7SKeshava Munegowda { 12916fa3dc7SKeshava Munegowda return __raw_readl(base + reg); 13016fa3dc7SKeshava Munegowda } 13116fa3dc7SKeshava Munegowda 13216fa3dc7SKeshava Munegowda static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) 13316fa3dc7SKeshava Munegowda { 13416fa3dc7SKeshava Munegowda __raw_writeb(val, base + reg); 13516fa3dc7SKeshava Munegowda } 13616fa3dc7SKeshava Munegowda 13716fa3dc7SKeshava Munegowda static inline u8 usbtll_readb(void __iomem *base, u8 reg) 13816fa3dc7SKeshava Munegowda { 13916fa3dc7SKeshava Munegowda return __raw_readb(base + reg); 14016fa3dc7SKeshava Munegowda } 14116fa3dc7SKeshava Munegowda 14216fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 14316fa3dc7SKeshava Munegowda 14416fa3dc7SKeshava Munegowda static bool is_ohci_port(enum usbhs_omap_port_mode pmode) 14516fa3dc7SKeshava Munegowda { 14616fa3dc7SKeshava Munegowda switch (pmode) { 14716fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: 14816fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: 14916fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: 15016fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: 15116fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: 15216fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: 15316fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: 15416fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: 15516fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: 15616fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: 15716fa3dc7SKeshava Munegowda return true; 15816fa3dc7SKeshava Munegowda 15916fa3dc7SKeshava Munegowda default: 16016fa3dc7SKeshava Munegowda return false; 16116fa3dc7SKeshava Munegowda } 16216fa3dc7SKeshava Munegowda } 16316fa3dc7SKeshava Munegowda 16416fa3dc7SKeshava Munegowda /* 16516fa3dc7SKeshava Munegowda * convert the port-mode enum to a value we can use in the FSLSMODE 16616fa3dc7SKeshava Munegowda * field of USBTLL_CHANNEL_CONF 16716fa3dc7SKeshava Munegowda */ 16816fa3dc7SKeshava Munegowda static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) 16916fa3dc7SKeshava Munegowda { 17016fa3dc7SKeshava Munegowda switch (mode) { 17116fa3dc7SKeshava Munegowda case OMAP_USBHS_PORT_MODE_UNUSED: 17216fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: 17316fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; 17416fa3dc7SKeshava Munegowda 17516fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: 17616fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; 17716fa3dc7SKeshava Munegowda 17816fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: 17916fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_3PIN_PHY; 18016fa3dc7SKeshava Munegowda 18116fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: 18216fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_4PIN_PHY; 18316fa3dc7SKeshava Munegowda 18416fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: 18516fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; 18616fa3dc7SKeshava Munegowda 18716fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: 18816fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; 18916fa3dc7SKeshava Munegowda 19016fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: 19116fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_3PIN_TLL; 19216fa3dc7SKeshava Munegowda 19316fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: 19416fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_4PIN_TLL; 19516fa3dc7SKeshava Munegowda 19616fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: 19716fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; 19816fa3dc7SKeshava Munegowda 19916fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: 20016fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; 20116fa3dc7SKeshava Munegowda default: 20216fa3dc7SKeshava Munegowda pr_warn("Invalid port mode, using default\n"); 20316fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; 20416fa3dc7SKeshava Munegowda } 20516fa3dc7SKeshava Munegowda } 20616fa3dc7SKeshava Munegowda 20716fa3dc7SKeshava Munegowda /** 20816fa3dc7SKeshava Munegowda * usbtll_omap_probe - initialize TI-based HCDs 20916fa3dc7SKeshava Munegowda * 21016fa3dc7SKeshava Munegowda * Allocates basic resources for this USB host controller. 21116fa3dc7SKeshava Munegowda */ 212f791be49SBill Pemberton static int usbtll_omap_probe(struct platform_device *pdev) 21316fa3dc7SKeshava Munegowda { 21416fa3dc7SKeshava Munegowda struct device *dev = &pdev->dev; 21516fa3dc7SKeshava Munegowda struct resource *res; 21616fa3dc7SKeshava Munegowda struct usbtll_omap *tll; 21716fa3dc7SKeshava Munegowda int ret = 0; 2187e0ff103SRoger Quadros int i, ver; 21916fa3dc7SKeshava Munegowda 22016fa3dc7SKeshava Munegowda dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); 22116fa3dc7SKeshava Munegowda 2221a7a8d70SRoger Quadros tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL); 22316fa3dc7SKeshava Munegowda if (!tll) { 22416fa3dc7SKeshava Munegowda dev_err(dev, "Memory allocation failed\n"); 2251a7a8d70SRoger Quadros return -ENOMEM; 22616fa3dc7SKeshava Munegowda } 22716fa3dc7SKeshava Munegowda 22816fa3dc7SKeshava Munegowda res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 229651da3d4SSachin Kamat tll->base = devm_ioremap_resource(dev, res); 230651da3d4SSachin Kamat if (IS_ERR(tll->base)) 231651da3d4SSachin Kamat return PTR_ERR(tll->base); 23216fa3dc7SKeshava Munegowda 23316fa3dc7SKeshava Munegowda platform_set_drvdata(pdev, tll); 23416fa3dc7SKeshava Munegowda pm_runtime_enable(dev); 23516fa3dc7SKeshava Munegowda pm_runtime_get_sync(dev); 23616fa3dc7SKeshava Munegowda 2379f4a3eceSRoger Quadros ver = usbtll_read(tll->base, OMAP_USBTLL_REVISION); 23816fa3dc7SKeshava Munegowda switch (ver) { 23916fa3dc7SKeshava Munegowda case OMAP_USBTLL_REV1: 240300c2f8fSRoger Quadros case OMAP_USBTLL_REV4: 2417e0ff103SRoger Quadros tll->nch = OMAP_TLL_CHANNEL_COUNT; 24216fa3dc7SKeshava Munegowda break; 2437e0ff103SRoger Quadros case OMAP_USBTLL_REV2: 24416fa3dc7SKeshava Munegowda case OMAP_USBTLL_REV3: 2457e0ff103SRoger Quadros tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT; 24616fa3dc7SKeshava Munegowda break; 24716fa3dc7SKeshava Munegowda default: 2487e0ff103SRoger Quadros tll->nch = OMAP_TLL_CHANNEL_COUNT; 2497e0ff103SRoger Quadros dev_dbg(dev, 2507e0ff103SRoger Quadros "USB TLL Rev : 0x%x not recognized, assuming %d channels\n", 2517e0ff103SRoger Quadros ver, tll->nch); 2527e0ff103SRoger Quadros break; 25316fa3dc7SKeshava Munegowda } 25416fa3dc7SKeshava Munegowda 2550bde3e9fSRoger Quadros tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]), 2560bde3e9fSRoger Quadros GFP_KERNEL); 2570bde3e9fSRoger Quadros if (!tll->ch_clk) { 2580bde3e9fSRoger Quadros ret = -ENOMEM; 2590bde3e9fSRoger Quadros dev_err(dev, "Couldn't allocate memory for channel clocks\n"); 2600bde3e9fSRoger Quadros goto err_clk_alloc; 2610bde3e9fSRoger Quadros } 2620bde3e9fSRoger Quadros 2630bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 2640bde3e9fSRoger Quadros char clkname[] = "usb_tll_hs_usb_chx_clk"; 2650bde3e9fSRoger Quadros 2660bde3e9fSRoger Quadros snprintf(clkname, sizeof(clkname), 2670bde3e9fSRoger Quadros "usb_tll_hs_usb_ch%d_clk", i); 2680bde3e9fSRoger Quadros tll->ch_clk[i] = clk_get(dev, clkname); 2690bde3e9fSRoger Quadros 2700bde3e9fSRoger Quadros if (IS_ERR(tll->ch_clk[i])) 2710bde3e9fSRoger Quadros dev_dbg(dev, "can't get clock : %s\n", clkname); 2720bde3e9fSRoger Quadros } 2730bde3e9fSRoger Quadros 2749f4a3eceSRoger Quadros pm_runtime_put_sync(dev); 2759f4a3eceSRoger Quadros /* only after this can omap_tll_enable/disable work */ 2769f4a3eceSRoger Quadros spin_lock(&tll_lock); 2779f4a3eceSRoger Quadros tll_dev = dev; 2789f4a3eceSRoger Quadros spin_unlock(&tll_lock); 2799f4a3eceSRoger Quadros 2809f4a3eceSRoger Quadros return 0; 2819f4a3eceSRoger Quadros 2829f4a3eceSRoger Quadros err_clk_alloc: 2839f4a3eceSRoger Quadros pm_runtime_put_sync(dev); 2849f4a3eceSRoger Quadros pm_runtime_disable(dev); 2859f4a3eceSRoger Quadros 2869f4a3eceSRoger Quadros return ret; 2879f4a3eceSRoger Quadros } 2889f4a3eceSRoger Quadros 2899f4a3eceSRoger Quadros /** 2909f4a3eceSRoger Quadros * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs 2919f4a3eceSRoger Quadros * @pdev: USB Host Controller being removed 2929f4a3eceSRoger Quadros * 2939f4a3eceSRoger Quadros * Reverses the effect of usbtll_omap_probe(). 2949f4a3eceSRoger Quadros */ 2959f4a3eceSRoger Quadros static int usbtll_omap_remove(struct platform_device *pdev) 2969f4a3eceSRoger Quadros { 2979f4a3eceSRoger Quadros struct usbtll_omap *tll = platform_get_drvdata(pdev); 2989f4a3eceSRoger Quadros int i; 2999f4a3eceSRoger Quadros 3009f4a3eceSRoger Quadros spin_lock(&tll_lock); 3019f4a3eceSRoger Quadros tll_dev = NULL; 3029f4a3eceSRoger Quadros spin_unlock(&tll_lock); 3039f4a3eceSRoger Quadros 3049f4a3eceSRoger Quadros for (i = 0; i < tll->nch; i++) 3059f4a3eceSRoger Quadros if (!IS_ERR(tll->ch_clk[i])) 3069f4a3eceSRoger Quadros clk_put(tll->ch_clk[i]); 3079f4a3eceSRoger Quadros 3089f4a3eceSRoger Quadros pm_runtime_disable(&pdev->dev); 3099f4a3eceSRoger Quadros return 0; 3109f4a3eceSRoger Quadros } 3119f4a3eceSRoger Quadros 31248130b8fSRoger Quadros static const struct of_device_id usbtll_omap_dt_ids[] = { 31348130b8fSRoger Quadros { .compatible = "ti,usbhs-tll" }, 31448130b8fSRoger Quadros { } 31548130b8fSRoger Quadros }; 31648130b8fSRoger Quadros 31748130b8fSRoger Quadros MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids); 31848130b8fSRoger Quadros 3199f4a3eceSRoger Quadros static struct platform_driver usbtll_omap_driver = { 3209f4a3eceSRoger Quadros .driver = { 3219f4a3eceSRoger Quadros .name = (char *)usbtll_driver_name, 3229f4a3eceSRoger Quadros .owner = THIS_MODULE, 3230f54e1e1SSachin Kamat .of_match_table = usbtll_omap_dt_ids, 3249f4a3eceSRoger Quadros }, 3259f4a3eceSRoger Quadros .probe = usbtll_omap_probe, 3269f4a3eceSRoger Quadros .remove = usbtll_omap_remove, 3279f4a3eceSRoger Quadros }; 3289f4a3eceSRoger Quadros 3299f4a3eceSRoger Quadros int omap_tll_init(struct usbhs_omap_platform_data *pdata) 3309f4a3eceSRoger Quadros { 3319f4a3eceSRoger Quadros int i; 3329f4a3eceSRoger Quadros bool needs_tll; 3339f4a3eceSRoger Quadros unsigned reg; 3349f4a3eceSRoger Quadros struct usbtll_omap *tll; 3359f4a3eceSRoger Quadros 3369f4a3eceSRoger Quadros spin_lock(&tll_lock); 3379f4a3eceSRoger Quadros 3389f4a3eceSRoger Quadros if (!tll_dev) { 3399f4a3eceSRoger Quadros spin_unlock(&tll_lock); 3409f4a3eceSRoger Quadros return -ENODEV; 3419f4a3eceSRoger Quadros } 3429f4a3eceSRoger Quadros 3439f4a3eceSRoger Quadros tll = dev_get_drvdata(tll_dev); 3449f4a3eceSRoger Quadros 34532a51f2aSRoger Quadros needs_tll = false; 34632a51f2aSRoger Quadros for (i = 0; i < tll->nch; i++) 34732a51f2aSRoger Quadros needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); 34832a51f2aSRoger Quadros 3499f4a3eceSRoger Quadros pm_runtime_get_sync(tll_dev); 3509f4a3eceSRoger Quadros 35132a51f2aSRoger Quadros if (needs_tll) { 3529f4a3eceSRoger Quadros void __iomem *base = tll->base; 35316fa3dc7SKeshava Munegowda 35416fa3dc7SKeshava Munegowda /* Program Common TLL register */ 35516fa3dc7SKeshava Munegowda reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); 35616fa3dc7SKeshava Munegowda reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON 35716fa3dc7SKeshava Munegowda | OMAP_TLL_SHARED_CONF_USB_DIVRATION); 35816fa3dc7SKeshava Munegowda reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; 35916fa3dc7SKeshava Munegowda reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; 36016fa3dc7SKeshava Munegowda 36116fa3dc7SKeshava Munegowda usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); 36216fa3dc7SKeshava Munegowda 36316fa3dc7SKeshava Munegowda /* Enable channels now */ 3647e0ff103SRoger Quadros for (i = 0; i < tll->nch; i++) { 36516fa3dc7SKeshava Munegowda reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); 36616fa3dc7SKeshava Munegowda 36716fa3dc7SKeshava Munegowda if (is_ohci_port(pdata->port_mode[i])) { 36816fa3dc7SKeshava Munegowda reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) 36916fa3dc7SKeshava Munegowda << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; 37016fa3dc7SKeshava Munegowda reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; 37116fa3dc7SKeshava Munegowda } else if (pdata->port_mode[i] == 37216fa3dc7SKeshava Munegowda OMAP_EHCI_PORT_MODE_TLL) { 37316fa3dc7SKeshava Munegowda /* 37416fa3dc7SKeshava Munegowda * Disable AutoIdle, BitStuffing 37516fa3dc7SKeshava Munegowda * and use SDR Mode 37616fa3dc7SKeshava Munegowda */ 37716fa3dc7SKeshava Munegowda reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE 37816fa3dc7SKeshava Munegowda | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF 37916fa3dc7SKeshava Munegowda | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); 380300c2f8fSRoger Quadros } else if (pdata->port_mode[i] == 381300c2f8fSRoger Quadros OMAP_EHCI_PORT_MODE_HSIC) { 382300c2f8fSRoger Quadros /* 383300c2f8fSRoger Quadros * HSIC Mode requires UTMI port configurations 384300c2f8fSRoger Quadros */ 385300c2f8fSRoger Quadros reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS 386300c2f8fSRoger Quadros | OMAP_TLL_CHANNEL_CONF_CHRGVBUS 387300c2f8fSRoger Quadros | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI 388300c2f8fSRoger Quadros | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF; 38916fa3dc7SKeshava Munegowda } else { 39016fa3dc7SKeshava Munegowda continue; 39116fa3dc7SKeshava Munegowda } 39216fa3dc7SKeshava Munegowda reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; 39316fa3dc7SKeshava Munegowda usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg); 39416fa3dc7SKeshava Munegowda 39516fa3dc7SKeshava Munegowda usbtll_writeb(base, 39616fa3dc7SKeshava Munegowda OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 39716fa3dc7SKeshava Munegowda 0xbe); 39816fa3dc7SKeshava Munegowda } 39916fa3dc7SKeshava Munegowda } 40016fa3dc7SKeshava Munegowda 4019f4a3eceSRoger Quadros pm_runtime_put_sync(tll_dev); 4029f4a3eceSRoger Quadros 40366751446SRoger Quadros spin_unlock(&tll_lock); 40416fa3dc7SKeshava Munegowda 4051a7a8d70SRoger Quadros return 0; 40616fa3dc7SKeshava Munegowda } 4079f4a3eceSRoger Quadros EXPORT_SYMBOL_GPL(omap_tll_init); 40816fa3dc7SKeshava Munegowda 4099f4a3eceSRoger Quadros int omap_tll_enable(struct usbhs_omap_platform_data *pdata) 41016fa3dc7SKeshava Munegowda { 4110bde3e9fSRoger Quadros int i; 4129f4a3eceSRoger Quadros struct usbtll_omap *tll; 41316fa3dc7SKeshava Munegowda 41466751446SRoger Quadros spin_lock(&tll_lock); 4159f4a3eceSRoger Quadros 4169f4a3eceSRoger Quadros if (!tll_dev) { 41766751446SRoger Quadros spin_unlock(&tll_lock); 4189f4a3eceSRoger Quadros return -ENODEV; 41916fa3dc7SKeshava Munegowda } 42016fa3dc7SKeshava Munegowda 4219f4a3eceSRoger Quadros tll = dev_get_drvdata(tll_dev); 42216fa3dc7SKeshava Munegowda 4239f4a3eceSRoger Quadros pm_runtime_get_sync(tll_dev); 42416fa3dc7SKeshava Munegowda 4250bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 42632a51f2aSRoger Quadros if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { 4270bde3e9fSRoger Quadros int r; 42816fa3dc7SKeshava Munegowda 4290bde3e9fSRoger Quadros if (IS_ERR(tll->ch_clk[i])) 4300bde3e9fSRoger Quadros continue; 4310bde3e9fSRoger Quadros 4320bde3e9fSRoger Quadros r = clk_enable(tll->ch_clk[i]); 4330bde3e9fSRoger Quadros if (r) { 4349f4a3eceSRoger Quadros dev_err(tll_dev, 4350bde3e9fSRoger Quadros "Error enabling ch %d clock: %d\n", i, r); 4360bde3e9fSRoger Quadros } 4370bde3e9fSRoger Quadros } 4380bde3e9fSRoger Quadros } 43916fa3dc7SKeshava Munegowda 4409f4a3eceSRoger Quadros spin_unlock(&tll_lock); 4419f4a3eceSRoger Quadros 44216fa3dc7SKeshava Munegowda return 0; 44316fa3dc7SKeshava Munegowda } 4449f4a3eceSRoger Quadros EXPORT_SYMBOL_GPL(omap_tll_enable); 44516fa3dc7SKeshava Munegowda 4469f4a3eceSRoger Quadros int omap_tll_disable(struct usbhs_omap_platform_data *pdata) 44716fa3dc7SKeshava Munegowda { 4480bde3e9fSRoger Quadros int i; 4499f4a3eceSRoger Quadros struct usbtll_omap *tll; 45016fa3dc7SKeshava Munegowda 4519f4a3eceSRoger Quadros spin_lock(&tll_lock); 4529f4a3eceSRoger Quadros 4539f4a3eceSRoger Quadros if (!tll_dev) { 4549f4a3eceSRoger Quadros spin_unlock(&tll_lock); 4559f4a3eceSRoger Quadros return -ENODEV; 4569f4a3eceSRoger Quadros } 4579f4a3eceSRoger Quadros 4589f4a3eceSRoger Quadros tll = dev_get_drvdata(tll_dev); 45916fa3dc7SKeshava Munegowda 4600bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 46132a51f2aSRoger Quadros if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { 4620bde3e9fSRoger Quadros if (!IS_ERR(tll->ch_clk[i])) 4630bde3e9fSRoger Quadros clk_disable(tll->ch_clk[i]); 4640bde3e9fSRoger Quadros } 4650bde3e9fSRoger Quadros } 46616fa3dc7SKeshava Munegowda 4679f4a3eceSRoger Quadros pm_runtime_put_sync(tll_dev); 4689f4a3eceSRoger Quadros 4699f4a3eceSRoger Quadros spin_unlock(&tll_lock); 4709f4a3eceSRoger Quadros 47116fa3dc7SKeshava Munegowda return 0; 47216fa3dc7SKeshava Munegowda } 47316fa3dc7SKeshava Munegowda EXPORT_SYMBOL_GPL(omap_tll_disable); 47416fa3dc7SKeshava Munegowda 47516fa3dc7SKeshava Munegowda MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); 47648130b8fSRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); 47716fa3dc7SKeshava Munegowda MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); 47816fa3dc7SKeshava Munegowda MODULE_LICENSE("GPL v2"); 47916fa3dc7SKeshava Munegowda MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); 48016fa3dc7SKeshava Munegowda 48116fa3dc7SKeshava Munegowda static int __init omap_usbtll_drvinit(void) 48216fa3dc7SKeshava Munegowda { 48316fa3dc7SKeshava Munegowda return platform_driver_register(&usbtll_omap_driver); 48416fa3dc7SKeshava Munegowda } 48516fa3dc7SKeshava Munegowda 48616fa3dc7SKeshava Munegowda /* 48716fa3dc7SKeshava Munegowda * init before usbhs core driver; 48816fa3dc7SKeshava Munegowda * The usbtll driver should be initialized before 48916fa3dc7SKeshava Munegowda * the usbhs core driver probe function is called. 49016fa3dc7SKeshava Munegowda */ 49116fa3dc7SKeshava Munegowda fs_initcall(omap_usbtll_drvinit); 49216fa3dc7SKeshava Munegowda 49316fa3dc7SKeshava Munegowda static void __exit omap_usbtll_drvexit(void) 49416fa3dc7SKeshava Munegowda { 49516fa3dc7SKeshava Munegowda platform_driver_unregister(&usbtll_omap_driver); 49616fa3dc7SKeshava Munegowda } 49716fa3dc7SKeshava Munegowda module_exit(omap_usbtll_drvexit); 498