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 #include <linux/types.h> 25 #include <linux/delay.h> 26 #include <linux/clk.h> 27 #include <linux/io.h> 28 #include <linux/err.h> 29 #include <linux/usb.h> 30 31 #include <plat/usb.h> 32 33 /* OMAP control module register for UTMI PHY */ 34 #define CONTROL_DEV_CONF 0x300 35 #define PHY_PD 0x1 36 37 #define USBOTGHS_CONTROL 0x33c 38 #define AVALID BIT(0) 39 #define BVALID BIT(1) 40 #define VBUSVALID BIT(2) 41 #define SESSEND BIT(3) 42 #define IDDIG BIT(4) 43 44 static struct clk *phyclk, *clk48m, *clk32k; 45 static void __iomem *ctrl_base; 46 47 int omap4430_phy_init(struct device *dev) 48 { 49 ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K); 50 if (!ctrl_base) { 51 dev_err(dev, "control module ioremap failed\n"); 52 return -ENOMEM; 53 } 54 /* Power down the phy */ 55 __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF); 56 phyclk = clk_get(dev, "ocp2scp_usb_phy_ick"); 57 58 if (IS_ERR(phyclk)) { 59 dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n"); 60 iounmap(ctrl_base); 61 return PTR_ERR(phyclk); 62 } 63 64 clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m"); 65 if (IS_ERR(clk48m)) { 66 dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n"); 67 clk_put(phyclk); 68 iounmap(ctrl_base); 69 return PTR_ERR(clk48m); 70 } 71 72 clk32k = clk_get(dev, "usb_phy_cm_clk32k"); 73 if (IS_ERR(clk32k)) { 74 dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n"); 75 clk_put(phyclk); 76 clk_put(clk48m); 77 iounmap(ctrl_base); 78 return PTR_ERR(clk32k); 79 } 80 return 0; 81 } 82 83 int omap4430_phy_set_clk(struct device *dev, int on) 84 { 85 static int state; 86 87 if (on && !state) { 88 /* Enable the phy clocks */ 89 clk_enable(phyclk); 90 clk_enable(clk48m); 91 clk_enable(clk32k); 92 state = 1; 93 } else if (state) { 94 /* Disable the phy clocks */ 95 clk_disable(phyclk); 96 clk_disable(clk48m); 97 clk_disable(clk32k); 98 state = 0; 99 } 100 return 0; 101 } 102 103 int omap4430_phy_power(struct device *dev, int ID, int on) 104 { 105 if (on) { 106 /* enabled the clocks */ 107 omap4430_phy_set_clk(dev, 1); 108 /* power on the phy */ 109 if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) { 110 __raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF); 111 mdelay(200); 112 } 113 if (ID) 114 /* enable VBUS valid, IDDIG groung */ 115 __raw_writel(AVALID | VBUSVALID, ctrl_base + 116 USBOTGHS_CONTROL); 117 else 118 /* 119 * Enable VBUS Valid, AValid and IDDIG 120 * high impedence 121 */ 122 __raw_writel(IDDIG | AVALID | VBUSVALID, 123 ctrl_base + USBOTGHS_CONTROL); 124 } else { 125 /* Enable session END and IDIG to high impedence. */ 126 __raw_writel(SESSEND | IDDIG, ctrl_base + 127 USBOTGHS_CONTROL); 128 /* Disable the clocks */ 129 omap4430_phy_set_clk(dev, 0); 130 /* Power down the phy */ 131 __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF); 132 } 133 134 return 0; 135 } 136 137 int omap4430_phy_exit(struct device *dev) 138 { 139 if (ctrl_base) 140 iounmap(ctrl_base); 141 if (phyclk) 142 clk_put(phyclk); 143 if (clk48m) 144 clk_put(clk48m); 145 if (clk32k) 146 clk_put(clk32k); 147 148 return 0; 149 } 150