16b1baefeSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 216fa3dc7SKeshava Munegowda /** 316fa3dc7SKeshava Munegowda * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI 416fa3dc7SKeshava Munegowda * 59f4a3eceSRoger Quadros * Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com 616fa3dc7SKeshava Munegowda * Author: Keshava Munegowda <keshava_mgowda@ti.com> 79f4a3eceSRoger Quadros * Author: Roger Quadros <rogerq@ti.com> 816fa3dc7SKeshava Munegowda */ 916fa3dc7SKeshava Munegowda #include <linux/kernel.h> 1016fa3dc7SKeshava Munegowda #include <linux/module.h> 1116fa3dc7SKeshava Munegowda #include <linux/types.h> 1216fa3dc7SKeshava Munegowda #include <linux/slab.h> 1316fa3dc7SKeshava Munegowda #include <linux/spinlock.h> 1416fa3dc7SKeshava Munegowda #include <linux/platform_device.h> 1516fa3dc7SKeshava Munegowda #include <linux/clk.h> 1616fa3dc7SKeshava Munegowda #include <linux/io.h> 1716fa3dc7SKeshava Munegowda #include <linux/err.h> 1816fa3dc7SKeshava Munegowda #include <linux/pm_runtime.h> 19e8c4a7acSFelipe Balbi #include <linux/platform_data/usb-omap.h> 2048130b8fSRoger Quadros #include <linux/of.h> 2116fa3dc7SKeshava Munegowda 2217ed4d22SBen Dooks #include "omap-usb.h" 2317ed4d22SBen Dooks 2416fa3dc7SKeshava Munegowda #define USBTLL_DRIVER_NAME "usbhs_tll" 2516fa3dc7SKeshava Munegowda 2616fa3dc7SKeshava Munegowda /* TLL Register Set */ 2716fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REVISION (0x00) 2816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG (0x10) 2916fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) 3016fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) 3116fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) 3216fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) 3316fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) 3416fa3dc7SKeshava Munegowda 3516fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSSTATUS (0x14) 3616fa3dc7SKeshava Munegowda #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) 3716fa3dc7SKeshava Munegowda 3816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_IRQSTATUS (0x18) 3916fa3dc7SKeshava Munegowda #define OMAP_USBTLL_IRQENABLE (0x1C) 4016fa3dc7SKeshava Munegowda 4116fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF (0x30) 4216fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) 4316fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) 4416fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) 4516fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) 4616fa3dc7SKeshava Munegowda #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) 4716fa3dc7SKeshava Munegowda 4816fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) 4916fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 50300c2f8fSRoger Quadros #define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16) 51300c2f8fSRoger Quadros #define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15) 5216fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) 5316fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) 5416fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) 5516fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) 56300c2f8fSRoger Quadros #define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI (2 << 1) 5716fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) 5816fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) 5916fa3dc7SKeshava Munegowda 6016fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 6116fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 6216fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 6316fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 6416fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 6516fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 6616fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 6716fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 6816fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA 6916fa3dc7SKeshava Munegowda #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB 7016fa3dc7SKeshava Munegowda 7116fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) 7216fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) 7316fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) 7416fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) 7516fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) 7616fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) 7716fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) 7816fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) 7916fa3dc7SKeshava Munegowda #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) 8016fa3dc7SKeshava Munegowda 8116fa3dc7SKeshava Munegowda #define OMAP_REV2_TLL_CHANNEL_COUNT 2 8216fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_COUNT 3 8316fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) 8416fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) 8516fa3dc7SKeshava Munegowda #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) 8616fa3dc7SKeshava Munegowda 8716fa3dc7SKeshava Munegowda /* Values of USBTLL_REVISION - Note: these are not given in the TRM */ 8816fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ 8916fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ 9016fa3dc7SKeshava Munegowda #define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ 91300c2f8fSRoger Quadros #define OMAP_USBTLL_REV4 0x00000006 /* OMAP5 */ 9216fa3dc7SKeshava Munegowda 9316fa3dc7SKeshava Munegowda #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) 9416fa3dc7SKeshava Munegowda 9532a51f2aSRoger Quadros /* only PHY and UNUSED modes don't need TLL */ 9632a51f2aSRoger Quadros #define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\ 9732a51f2aSRoger Quadros (x) != OMAP_EHCI_PORT_MODE_PHY) 9832a51f2aSRoger Quadros 9916fa3dc7SKeshava Munegowda struct usbtll_omap { 1009f4a3eceSRoger Quadros void __iomem *base; 10116c2004dSLadislav Michl int nch; /* num. of channels */ 102a0c8498cSGustavo A. R. Silva struct clk *ch_clk[]; /* must be the last member */ 10316fa3dc7SKeshava Munegowda }; 10416fa3dc7SKeshava Munegowda 10516fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 10616fa3dc7SKeshava Munegowda 1077ed86191SRoger Quadros static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; 1087ed86191SRoger Quadros static struct device *tll_dev; 10966751446SRoger Quadros static DEFINE_SPINLOCK(tll_lock); /* serialize access to tll_dev */ 11016fa3dc7SKeshava Munegowda 11116fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 11216fa3dc7SKeshava Munegowda 11316fa3dc7SKeshava Munegowda static inline void usbtll_write(void __iomem *base, u32 reg, u32 val) 11416fa3dc7SKeshava Munegowda { 115dd6eb26fSVictor Kamensky writel_relaxed(val, base + reg); 11616fa3dc7SKeshava Munegowda } 11716fa3dc7SKeshava Munegowda 11816fa3dc7SKeshava Munegowda static inline u32 usbtll_read(void __iomem *base, u32 reg) 11916fa3dc7SKeshava Munegowda { 120dd6eb26fSVictor Kamensky return readl_relaxed(base + reg); 12116fa3dc7SKeshava Munegowda } 12216fa3dc7SKeshava Munegowda 123993dc737SArnd Bergmann static inline void usbtll_writeb(void __iomem *base, u32 reg, u8 val) 12416fa3dc7SKeshava Munegowda { 125dd6eb26fSVictor Kamensky writeb_relaxed(val, base + reg); 12616fa3dc7SKeshava Munegowda } 12716fa3dc7SKeshava Munegowda 128993dc737SArnd Bergmann static inline u8 usbtll_readb(void __iomem *base, u32 reg) 12916fa3dc7SKeshava Munegowda { 130dd6eb26fSVictor Kamensky return readb_relaxed(base + reg); 13116fa3dc7SKeshava Munegowda } 13216fa3dc7SKeshava Munegowda 13316fa3dc7SKeshava Munegowda /*-------------------------------------------------------------------------*/ 13416fa3dc7SKeshava Munegowda 13516fa3dc7SKeshava Munegowda static bool is_ohci_port(enum usbhs_omap_port_mode pmode) 13616fa3dc7SKeshava Munegowda { 13716fa3dc7SKeshava Munegowda switch (pmode) { 13816fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: 13916fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: 14016fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: 14116fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: 14216fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: 14316fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: 14416fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: 14516fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: 14616fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: 14716fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: 14816fa3dc7SKeshava Munegowda return true; 14916fa3dc7SKeshava Munegowda 15016fa3dc7SKeshava Munegowda default: 15116fa3dc7SKeshava Munegowda return false; 15216fa3dc7SKeshava Munegowda } 15316fa3dc7SKeshava Munegowda } 15416fa3dc7SKeshava Munegowda 15516fa3dc7SKeshava Munegowda /* 15616fa3dc7SKeshava Munegowda * convert the port-mode enum to a value we can use in the FSLSMODE 15716fa3dc7SKeshava Munegowda * field of USBTLL_CHANNEL_CONF 15816fa3dc7SKeshava Munegowda */ 15916fa3dc7SKeshava Munegowda static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) 16016fa3dc7SKeshava Munegowda { 16116fa3dc7SKeshava Munegowda switch (mode) { 16216fa3dc7SKeshava Munegowda case OMAP_USBHS_PORT_MODE_UNUSED: 16316fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: 16416fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; 16516fa3dc7SKeshava Munegowda 16616fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: 16716fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; 16816fa3dc7SKeshava Munegowda 16916fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: 17016fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_3PIN_PHY; 17116fa3dc7SKeshava Munegowda 17216fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: 17316fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_4PIN_PHY; 17416fa3dc7SKeshava Munegowda 17516fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: 17616fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; 17716fa3dc7SKeshava Munegowda 17816fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: 17916fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; 18016fa3dc7SKeshava Munegowda 18116fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: 18216fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_3PIN_TLL; 18316fa3dc7SKeshava Munegowda 18416fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: 18516fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_4PIN_TLL; 18616fa3dc7SKeshava Munegowda 18716fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: 18816fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; 18916fa3dc7SKeshava Munegowda 19016fa3dc7SKeshava Munegowda case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: 19116fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; 19216fa3dc7SKeshava Munegowda default: 19316fa3dc7SKeshava Munegowda pr_warn("Invalid port mode, using default\n"); 19416fa3dc7SKeshava Munegowda return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; 19516fa3dc7SKeshava Munegowda } 19616fa3dc7SKeshava Munegowda } 19716fa3dc7SKeshava Munegowda 19816fa3dc7SKeshava Munegowda /** 19916fa3dc7SKeshava Munegowda * usbtll_omap_probe - initialize TI-based HCDs 20016fa3dc7SKeshava Munegowda * 20116fa3dc7SKeshava Munegowda * Allocates basic resources for this USB host controller. 20216fa3dc7SKeshava Munegowda */ 203f791be49SBill Pemberton static int usbtll_omap_probe(struct platform_device *pdev) 20416fa3dc7SKeshava Munegowda { 20516fa3dc7SKeshava Munegowda struct device *dev = &pdev->dev; 20616fa3dc7SKeshava Munegowda struct resource *res; 20716fa3dc7SKeshava Munegowda struct usbtll_omap *tll; 20816c2004dSLadislav Michl void __iomem *base; 20916c2004dSLadislav Michl int i, nch, ver; 21016fa3dc7SKeshava Munegowda 21116fa3dc7SKeshava Munegowda dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); 21216fa3dc7SKeshava Munegowda 21316fa3dc7SKeshava Munegowda res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 21416c2004dSLadislav Michl base = devm_ioremap_resource(dev, res); 21516c2004dSLadislav Michl if (IS_ERR(base)) 21616c2004dSLadislav Michl return PTR_ERR(base); 21716fa3dc7SKeshava Munegowda 21816fa3dc7SKeshava Munegowda pm_runtime_enable(dev); 21916fa3dc7SKeshava Munegowda pm_runtime_get_sync(dev); 22016fa3dc7SKeshava Munegowda 22116c2004dSLadislav Michl ver = usbtll_read(base, OMAP_USBTLL_REVISION); 22216fa3dc7SKeshava Munegowda switch (ver) { 22316fa3dc7SKeshava Munegowda case OMAP_USBTLL_REV1: 224300c2f8fSRoger Quadros case OMAP_USBTLL_REV4: 22516c2004dSLadislav Michl nch = OMAP_TLL_CHANNEL_COUNT; 22616fa3dc7SKeshava Munegowda break; 2277e0ff103SRoger Quadros case OMAP_USBTLL_REV2: 22816fa3dc7SKeshava Munegowda case OMAP_USBTLL_REV3: 22916c2004dSLadislav Michl nch = OMAP_REV2_TLL_CHANNEL_COUNT; 23016fa3dc7SKeshava Munegowda break; 23116fa3dc7SKeshava Munegowda default: 23216c2004dSLadislav Michl nch = OMAP_TLL_CHANNEL_COUNT; 23316c2004dSLadislav Michl dev_dbg(dev, "rev 0x%x not recognized, assuming %d channels\n", 23416c2004dSLadislav Michl ver, nch); 2357e0ff103SRoger Quadros break; 23616fa3dc7SKeshava Munegowda } 23716fa3dc7SKeshava Munegowda 23816c2004dSLadislav Michl tll = devm_kzalloc(dev, sizeof(*tll) + sizeof(tll->ch_clk[nch]), 2390bde3e9fSRoger Quadros GFP_KERNEL); 24016c2004dSLadislav Michl if (!tll) { 24116c2004dSLadislav Michl pm_runtime_put_sync(dev); 24216c2004dSLadislav Michl pm_runtime_disable(dev); 24316c2004dSLadislav Michl return -ENOMEM; 2440bde3e9fSRoger Quadros } 2450bde3e9fSRoger Quadros 24616c2004dSLadislav Michl tll->base = base; 24716c2004dSLadislav Michl tll->nch = nch; 24816c2004dSLadislav Michl platform_set_drvdata(pdev, tll); 24916c2004dSLadislav Michl 25016c2004dSLadislav Michl for (i = 0; i < nch; i++) { 2510bde3e9fSRoger Quadros char clkname[] = "usb_tll_hs_usb_chx_clk"; 2520bde3e9fSRoger Quadros 2530bde3e9fSRoger Quadros snprintf(clkname, sizeof(clkname), 2540bde3e9fSRoger Quadros "usb_tll_hs_usb_ch%d_clk", i); 2550bde3e9fSRoger Quadros tll->ch_clk[i] = clk_get(dev, clkname); 2560bde3e9fSRoger Quadros 2570bde3e9fSRoger Quadros if (IS_ERR(tll->ch_clk[i])) 2580bde3e9fSRoger Quadros dev_dbg(dev, "can't get clock : %s\n", clkname); 259b49b927fSRoger Quadros else 260b49b927fSRoger Quadros clk_prepare(tll->ch_clk[i]); 2610bde3e9fSRoger Quadros } 2620bde3e9fSRoger Quadros 2639f4a3eceSRoger Quadros pm_runtime_put_sync(dev); 2649f4a3eceSRoger Quadros /* only after this can omap_tll_enable/disable work */ 2659f4a3eceSRoger Quadros spin_lock(&tll_lock); 2669f4a3eceSRoger Quadros tll_dev = dev; 2679f4a3eceSRoger Quadros spin_unlock(&tll_lock); 2689f4a3eceSRoger Quadros 2699f4a3eceSRoger Quadros return 0; 2709f4a3eceSRoger Quadros } 2719f4a3eceSRoger Quadros 2729f4a3eceSRoger Quadros /** 2739f4a3eceSRoger Quadros * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs 2749f4a3eceSRoger Quadros * @pdev: USB Host Controller being removed 2759f4a3eceSRoger Quadros * 2769f4a3eceSRoger Quadros * Reverses the effect of usbtll_omap_probe(). 2779f4a3eceSRoger Quadros */ 2789f4a3eceSRoger Quadros static int usbtll_omap_remove(struct platform_device *pdev) 2799f4a3eceSRoger Quadros { 2809f4a3eceSRoger Quadros struct usbtll_omap *tll = platform_get_drvdata(pdev); 2819f4a3eceSRoger Quadros int i; 2829f4a3eceSRoger Quadros 2839f4a3eceSRoger Quadros spin_lock(&tll_lock); 2849f4a3eceSRoger Quadros tll_dev = NULL; 2859f4a3eceSRoger Quadros spin_unlock(&tll_lock); 2869f4a3eceSRoger Quadros 287b49b927fSRoger Quadros for (i = 0; i < tll->nch; i++) { 288b49b927fSRoger Quadros if (!IS_ERR(tll->ch_clk[i])) { 289b49b927fSRoger Quadros clk_unprepare(tll->ch_clk[i]); 2909f4a3eceSRoger Quadros clk_put(tll->ch_clk[i]); 291b49b927fSRoger Quadros } 292b49b927fSRoger Quadros } 2939f4a3eceSRoger Quadros 2949f4a3eceSRoger Quadros pm_runtime_disable(&pdev->dev); 2959f4a3eceSRoger Quadros return 0; 2969f4a3eceSRoger Quadros } 2979f4a3eceSRoger Quadros 29848130b8fSRoger Quadros static const struct of_device_id usbtll_omap_dt_ids[] = { 29948130b8fSRoger Quadros { .compatible = "ti,usbhs-tll" }, 30048130b8fSRoger Quadros { } 30148130b8fSRoger Quadros }; 30248130b8fSRoger Quadros 30348130b8fSRoger Quadros MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids); 30448130b8fSRoger Quadros 3059f4a3eceSRoger Quadros static struct platform_driver usbtll_omap_driver = { 3069f4a3eceSRoger Quadros .driver = { 3079a153b0eSCorentin Labbe .name = usbtll_driver_name, 3080f54e1e1SSachin Kamat .of_match_table = usbtll_omap_dt_ids, 3099f4a3eceSRoger Quadros }, 3109f4a3eceSRoger Quadros .probe = usbtll_omap_probe, 3119f4a3eceSRoger Quadros .remove = usbtll_omap_remove, 3129f4a3eceSRoger Quadros }; 3139f4a3eceSRoger Quadros 3149f4a3eceSRoger Quadros int omap_tll_init(struct usbhs_omap_platform_data *pdata) 3159f4a3eceSRoger Quadros { 3169f4a3eceSRoger Quadros int i; 3179f4a3eceSRoger Quadros bool needs_tll; 3189f4a3eceSRoger Quadros unsigned reg; 3199f4a3eceSRoger Quadros struct usbtll_omap *tll; 3209f4a3eceSRoger Quadros 32176a0775dSRoger Quadros if (!tll_dev) 3229f4a3eceSRoger Quadros return -ENODEV; 3239f4a3eceSRoger Quadros 32476a0775dSRoger Quadros pm_runtime_get_sync(tll_dev); 32576a0775dSRoger Quadros 32676a0775dSRoger Quadros spin_lock(&tll_lock); 3279f4a3eceSRoger Quadros tll = dev_get_drvdata(tll_dev); 32832a51f2aSRoger Quadros needs_tll = false; 32932a51f2aSRoger Quadros for (i = 0; i < tll->nch; i++) 33032a51f2aSRoger Quadros needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); 33132a51f2aSRoger Quadros 33232a51f2aSRoger Quadros if (needs_tll) { 3339f4a3eceSRoger Quadros void __iomem *base = tll->base; 33416fa3dc7SKeshava Munegowda 33516fa3dc7SKeshava Munegowda /* Program Common TLL register */ 33616fa3dc7SKeshava Munegowda reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); 33716fa3dc7SKeshava Munegowda reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON 33816fa3dc7SKeshava Munegowda | OMAP_TLL_SHARED_CONF_USB_DIVRATION); 33916fa3dc7SKeshava Munegowda reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; 34016fa3dc7SKeshava Munegowda reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; 34116fa3dc7SKeshava Munegowda 34216fa3dc7SKeshava Munegowda usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); 34316fa3dc7SKeshava Munegowda 34416fa3dc7SKeshava Munegowda /* Enable channels now */ 3457e0ff103SRoger Quadros for (i = 0; i < tll->nch; i++) { 34616fa3dc7SKeshava Munegowda reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); 34716fa3dc7SKeshava Munegowda 34816fa3dc7SKeshava Munegowda if (is_ohci_port(pdata->port_mode[i])) { 34916fa3dc7SKeshava Munegowda reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) 35016fa3dc7SKeshava Munegowda << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; 35116fa3dc7SKeshava Munegowda reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; 35216fa3dc7SKeshava Munegowda } else if (pdata->port_mode[i] == 35316fa3dc7SKeshava Munegowda OMAP_EHCI_PORT_MODE_TLL) { 35416fa3dc7SKeshava Munegowda /* 35576d3341bSTony Lindgren * Disable UTMI AutoIdle, BitStuffing 35676d3341bSTony Lindgren * and use SDR Mode. Enable ULPI AutoIdle. 35716fa3dc7SKeshava Munegowda */ 35816fa3dc7SKeshava Munegowda reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE 35916fa3dc7SKeshava Munegowda | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); 3608b8a84c5STony Lindgren reg |= OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF; 36176d3341bSTony Lindgren reg |= OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE; 362300c2f8fSRoger Quadros } else if (pdata->port_mode[i] == 363300c2f8fSRoger Quadros OMAP_EHCI_PORT_MODE_HSIC) { 364300c2f8fSRoger Quadros /* 365300c2f8fSRoger Quadros * HSIC Mode requires UTMI port configurations 366300c2f8fSRoger Quadros */ 367300c2f8fSRoger Quadros reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS 368300c2f8fSRoger Quadros | OMAP_TLL_CHANNEL_CONF_CHRGVBUS 369300c2f8fSRoger Quadros | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI 370300c2f8fSRoger Quadros | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF; 37116fa3dc7SKeshava Munegowda } else { 37216fa3dc7SKeshava Munegowda continue; 37316fa3dc7SKeshava Munegowda } 37416fa3dc7SKeshava Munegowda reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; 37516fa3dc7SKeshava Munegowda usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg); 37616fa3dc7SKeshava Munegowda 37716fa3dc7SKeshava Munegowda usbtll_writeb(base, 37816fa3dc7SKeshava Munegowda OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 37916fa3dc7SKeshava Munegowda 0xbe); 38016fa3dc7SKeshava Munegowda } 38116fa3dc7SKeshava Munegowda } 38216fa3dc7SKeshava Munegowda 38366751446SRoger Quadros spin_unlock(&tll_lock); 38476a0775dSRoger Quadros pm_runtime_put_sync(tll_dev); 38516fa3dc7SKeshava Munegowda 3861a7a8d70SRoger Quadros return 0; 38716fa3dc7SKeshava Munegowda } 3889f4a3eceSRoger Quadros EXPORT_SYMBOL_GPL(omap_tll_init); 38916fa3dc7SKeshava Munegowda 3909f4a3eceSRoger Quadros int omap_tll_enable(struct usbhs_omap_platform_data *pdata) 39116fa3dc7SKeshava Munegowda { 3920bde3e9fSRoger Quadros int i; 3939f4a3eceSRoger Quadros struct usbtll_omap *tll; 39416fa3dc7SKeshava Munegowda 39576a0775dSRoger Quadros if (!tll_dev) 3969f4a3eceSRoger Quadros return -ENODEV; 39716fa3dc7SKeshava Munegowda 3989f4a3eceSRoger Quadros pm_runtime_get_sync(tll_dev); 39916fa3dc7SKeshava Munegowda 40076a0775dSRoger Quadros spin_lock(&tll_lock); 40176a0775dSRoger Quadros tll = dev_get_drvdata(tll_dev); 40276a0775dSRoger Quadros 4030bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 40432a51f2aSRoger Quadros if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { 4050bde3e9fSRoger Quadros int r; 40616fa3dc7SKeshava Munegowda 4070bde3e9fSRoger Quadros if (IS_ERR(tll->ch_clk[i])) 4080bde3e9fSRoger Quadros continue; 4090bde3e9fSRoger Quadros 410b49b927fSRoger Quadros r = clk_enable(tll->ch_clk[i]); 4110bde3e9fSRoger Quadros if (r) { 4129f4a3eceSRoger Quadros dev_err(tll_dev, 4130bde3e9fSRoger Quadros "Error enabling ch %d clock: %d\n", i, r); 4140bde3e9fSRoger Quadros } 4150bde3e9fSRoger Quadros } 4160bde3e9fSRoger Quadros } 41716fa3dc7SKeshava Munegowda 4189f4a3eceSRoger Quadros spin_unlock(&tll_lock); 4199f4a3eceSRoger Quadros 42016fa3dc7SKeshava Munegowda return 0; 42116fa3dc7SKeshava Munegowda } 4229f4a3eceSRoger Quadros EXPORT_SYMBOL_GPL(omap_tll_enable); 42316fa3dc7SKeshava Munegowda 4249f4a3eceSRoger Quadros int omap_tll_disable(struct usbhs_omap_platform_data *pdata) 42516fa3dc7SKeshava Munegowda { 4260bde3e9fSRoger Quadros int i; 4279f4a3eceSRoger Quadros struct usbtll_omap *tll; 42816fa3dc7SKeshava Munegowda 42976a0775dSRoger Quadros if (!tll_dev) 4309f4a3eceSRoger Quadros return -ENODEV; 4319f4a3eceSRoger Quadros 43276a0775dSRoger Quadros spin_lock(&tll_lock); 4339f4a3eceSRoger Quadros tll = dev_get_drvdata(tll_dev); 43416fa3dc7SKeshava Munegowda 4350bde3e9fSRoger Quadros for (i = 0; i < tll->nch; i++) { 43632a51f2aSRoger Quadros if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { 4370bde3e9fSRoger Quadros if (!IS_ERR(tll->ch_clk[i])) 438b49b927fSRoger Quadros clk_disable(tll->ch_clk[i]); 4390bde3e9fSRoger Quadros } 4400bde3e9fSRoger Quadros } 44116fa3dc7SKeshava Munegowda 4429f4a3eceSRoger Quadros spin_unlock(&tll_lock); 44376a0775dSRoger Quadros pm_runtime_put_sync(tll_dev); 4449f4a3eceSRoger Quadros 44516fa3dc7SKeshava Munegowda return 0; 44616fa3dc7SKeshava Munegowda } 44716fa3dc7SKeshava Munegowda EXPORT_SYMBOL_GPL(omap_tll_disable); 44816fa3dc7SKeshava Munegowda 44916fa3dc7SKeshava Munegowda MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); 45048130b8fSRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); 45116fa3dc7SKeshava Munegowda MODULE_LICENSE("GPL v2"); 45216fa3dc7SKeshava Munegowda MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); 45316fa3dc7SKeshava Munegowda 45416fa3dc7SKeshava Munegowda static int __init omap_usbtll_drvinit(void) 45516fa3dc7SKeshava Munegowda { 45616fa3dc7SKeshava Munegowda return platform_driver_register(&usbtll_omap_driver); 45716fa3dc7SKeshava Munegowda } 45816fa3dc7SKeshava Munegowda 45916fa3dc7SKeshava Munegowda /* 46016fa3dc7SKeshava Munegowda * init before usbhs core driver; 46116fa3dc7SKeshava Munegowda * The usbtll driver should be initialized before 46216fa3dc7SKeshava Munegowda * the usbhs core driver probe function is called. 46316fa3dc7SKeshava Munegowda */ 46416fa3dc7SKeshava Munegowda fs_initcall(omap_usbtll_drvinit); 46516fa3dc7SKeshava Munegowda 46616fa3dc7SKeshava Munegowda static void __exit omap_usbtll_drvexit(void) 46716fa3dc7SKeshava Munegowda { 46816fa3dc7SKeshava Munegowda platform_driver_unregister(&usbtll_omap_driver); 46916fa3dc7SKeshava Munegowda } 47016fa3dc7SKeshava Munegowda module_exit(omap_usbtll_drvexit); 471