1 /* 2 * This file configures the internal USB PHY in OMAP4430. Used 3 * with TWL6030 transceiver and MUSB on OMAP4430. 4 * 5 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * Author: Hema HK <hemahk@ti.com> 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * 22 */ 23 24 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 25 26 #include <linux/types.h> 27 #include <linux/delay.h> 28 #include <linux/clk.h> 29 #include <linux/io.h> 30 #include <linux/err.h> 31 #include <linux/usb.h> 32 #include <linux/usb/musb.h> 33 34 #include "soc.h" 35 #include "control.h" 36 #include "usb.h" 37 38 #define CONTROL_DEV_CONF 0x300 39 #define PHY_PD 0x1 40 41 /** 42 * omap4430_phy_power_down: disable MUSB PHY during early init 43 * 44 * OMAP4 MUSB PHY module is enabled by default on reset, but this will 45 * prevent core retention if not disabled by SW. USB driver will 46 * later on enable this, once and if the driver needs it. 47 */ 48 static int __init omap4430_phy_power_down(void) 49 { 50 void __iomem *ctrl_base; 51 52 if (!cpu_is_omap44xx()) 53 return 0; 54 55 ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K); 56 if (!ctrl_base) { 57 pr_err("control module ioremap failed\n"); 58 return -ENOMEM; 59 } 60 61 /* Power down the phy */ 62 writel_relaxed(PHY_PD, ctrl_base + CONTROL_DEV_CONF); 63 64 iounmap(ctrl_base); 65 66 return 0; 67 } 68 omap_early_initcall(omap4430_phy_power_down); 69 70 void am35x_musb_reset(void) 71 { 72 u32 regval; 73 74 /* Reset the musb interface */ 75 regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); 76 77 regval |= AM35XX_USBOTGSS_SW_RST; 78 omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); 79 80 regval &= ~AM35XX_USBOTGSS_SW_RST; 81 omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); 82 83 regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); 84 } 85 86 void am35x_musb_phy_power(u8 on) 87 { 88 unsigned long timeout = jiffies + msecs_to_jiffies(100); 89 u32 devconf2; 90 91 if (on) { 92 /* 93 * Start the on-chip PHY and its PLL. 94 */ 95 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); 96 97 devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN); 98 devconf2 |= CONF2_PHY_PLLON; 99 100 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); 101 102 pr_info("Waiting for PHY clock good...\n"); 103 while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2) 104 & CONF2_PHYCLKGD)) { 105 cpu_relax(); 106 107 if (time_after(jiffies, timeout)) { 108 pr_err("musb PHY clock good timed out\n"); 109 break; 110 } 111 } 112 } else { 113 /* 114 * Power down the on-chip PHY. 115 */ 116 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); 117 118 devconf2 &= ~CONF2_PHY_PLLON; 119 devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN; 120 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); 121 } 122 } 123 124 void am35x_musb_clear_irq(void) 125 { 126 u32 regval; 127 128 regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); 129 regval |= AM35XX_USBOTGSS_INT_CLR; 130 omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR); 131 regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); 132 } 133 134 void am35x_set_mode(u8 musb_mode) 135 { 136 u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); 137 138 devconf2 &= ~CONF2_OTGMODE; 139 switch (musb_mode) { 140 case MUSB_HOST: /* Force VBUS valid, ID = 0 */ 141 devconf2 |= CONF2_FORCE_HOST; 142 break; 143 case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */ 144 devconf2 |= CONF2_FORCE_DEVICE; 145 break; 146 case MUSB_OTG: /* Don't override the VBUS/ID comparators */ 147 devconf2 |= CONF2_NO_OVERRIDE; 148 break; 149 default: 150 pr_info("Unsupported mode %u\n", musb_mode); 151 } 152 153 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); 154 } 155 156 void ti81xx_musb_phy_power(u8 on) 157 { 158 void __iomem *scm_base = NULL; 159 u32 usbphycfg; 160 161 scm_base = ioremap(TI81XX_SCM_BASE, SZ_2K); 162 if (!scm_base) { 163 pr_err("system control module ioremap failed\n"); 164 return; 165 } 166 167 usbphycfg = readl_relaxed(scm_base + USBCTRL0); 168 169 if (on) { 170 if (cpu_is_ti816x()) { 171 usbphycfg |= TI816X_USBPHY0_NORMAL_MODE; 172 usbphycfg &= ~TI816X_USBPHY_REFCLK_OSC; 173 } else if (cpu_is_ti814x()) { 174 usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN 175 | USBPHY_DPINPUT | USBPHY_DMINPUT); 176 usbphycfg |= (USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN 177 | USBPHY_DPOPBUFCTL | USBPHY_DMOPBUFCTL); 178 } 179 } else { 180 if (cpu_is_ti816x()) 181 usbphycfg &= ~TI816X_USBPHY0_NORMAL_MODE; 182 else if (cpu_is_ti814x()) 183 usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; 184 185 } 186 writel_relaxed(usbphycfg, scm_base + USBCTRL0); 187 188 iounmap(scm_base); 189 } 190