1 /* 2 * Copyright (c) 2009 Wind River Systems, Inc. 3 * Tom Rix <Tom.Rix@windriver.com> 4 * 5 * This is file is based on 6 * repository git.gitorious.org/u-boot-omap3/mainline.git, 7 * branch omap3-dev-usb, file drivers/usb/gadget/twl4030_usb.c 8 * 9 * This is the unique part of its copyright : 10 * 11 * ------------------------------------------------------------------------ 12 * 13 * * (C) Copyright 2009 Atin Malaviya (atin.malaviya@gmail.com) 14 * 15 * Based on: twl4030_usb.c in linux 2.6 (drivers/i2c/chips/twl4030_usb.c) 16 * Copyright (C) 2004-2007 Texas Instruments 17 * Copyright (C) 2008 Nokia Corporation 18 * Contact: Felipe Balbi <felipe.balbi@nokia.com> 19 * 20 * Author: Atin Malaviya (atin.malaviya@gmail.com) 21 * 22 * ------------------------------------------------------------------------ 23 * 24 * SPDX-License-Identifier: GPL-2.0+ 25 */ 26 27 #include <twl4030.h> 28 29 /* Defines for bits in registers */ 30 #define OPMODE_MASK (3 << 3) 31 #define XCVRSELECT_MASK (3 << 0) 32 #define CARKITMODE (1 << 2) 33 #define OTG_ENAB (1 << 5) 34 #define PHYPWD (1 << 0) 35 #define CLOCKGATING_EN (1 << 2) 36 #define CLK32K_EN (1 << 1) 37 #define REQ_PHY_DPLL_CLK (1 << 0) 38 #define PHY_DPLL_CLK (1 << 0) 39 40 static int twl4030_usb_write(u8 address, u8 data) 41 { 42 int ret; 43 44 ret = twl4030_i2c_write_u8(TWL4030_CHIP_USB, address, data); 45 if (ret != 0) 46 printf("TWL4030:USB:Write[0x%x] Error %d\n", address, ret); 47 48 return ret; 49 } 50 51 static int twl4030_usb_read(u8 address) 52 { 53 u8 data; 54 int ret; 55 56 ret = twl4030_i2c_read_u8(TWL4030_CHIP_USB, address, &data); 57 if (ret == 0) 58 ret = data; 59 else 60 printf("TWL4030:USB:Read[0x%x] Error %d\n", address, ret); 61 62 return ret; 63 } 64 65 static void twl4030_usb_ldo_init(void) 66 { 67 /* Enable writing to power configuration registers */ 68 twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 69 TWL4030_PM_MASTER_PROTECT_KEY, 0xC0); 70 twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 71 TWL4030_PM_MASTER_PROTECT_KEY, 0x0C); 72 73 /* put VUSB3V1 LDO in active state */ 74 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 75 TWL4030_PM_RECEIVER_VUSB_DEDICATED2, 0x00); 76 77 /* input to VUSB3V1 LDO is from VBAT, not VBUS */ 78 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 79 TWL4030_PM_RECEIVER_VUSB_DEDICATED1, 0x14); 80 81 /* turn on 3.1V regulator */ 82 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 83 TWL4030_PM_RECEIVER_VUSB3V1_DEV_GRP, 0x20); 84 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 85 TWL4030_PM_RECEIVER_VUSB3V1_TYPE, 0x00); 86 87 /* turn on 1.5V regulator */ 88 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 89 TWL4030_PM_RECEIVER_VUSB1V5_DEV_GRP, 0x20); 90 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 91 TWL4030_PM_RECEIVER_VUSB1V5_TYPE, 0x00); 92 93 /* turn on 1.8V regulator */ 94 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 95 TWL4030_PM_RECEIVER_VUSB1V8_DEV_GRP, 0x20); 96 twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 97 TWL4030_PM_RECEIVER_VUSB1V8_TYPE, 0x00); 98 99 /* disable access to power configuration registers */ 100 twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 101 TWL4030_PM_MASTER_PROTECT_KEY, 0x00); 102 } 103 104 static void twl4030_phy_power(void) 105 { 106 u8 pwr, clk; 107 108 /* Power the PHY */ 109 pwr = twl4030_usb_read(TWL4030_USB_PHY_PWR_CTRL); 110 pwr &= ~PHYPWD; 111 twl4030_usb_write(TWL4030_USB_PHY_PWR_CTRL, pwr); 112 /* Enable clocks */ 113 clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL); 114 clk |= CLOCKGATING_EN | CLK32K_EN; 115 twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk); 116 } 117 118 /* 119 * Initiaze the ULPI interface 120 * ULPI : Universal Transceiver Macrocell Low Pin Interface 121 * An interface between the USB link controller like musb and the 122 * the PHY or transceiver that drives the actual bus. 123 */ 124 int twl4030_usb_ulpi_init(void) 125 { 126 long timeout = 1000 * 1000; /* 1 sec */; 127 u8 clk, sts, pwr; 128 129 /* twl4030 ldo init */ 130 twl4030_usb_ldo_init(); 131 132 /* Enable the twl4030 phy */ 133 twl4030_phy_power(); 134 135 /* Enable DPLL to access PHY registers over I2C */ 136 clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL); 137 clk |= REQ_PHY_DPLL_CLK; 138 twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk); 139 140 /* Check if the PHY DPLL is locked */ 141 sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS); 142 while (!(sts & PHY_DPLL_CLK) && 0 < timeout) { 143 udelay(10); 144 sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS); 145 timeout -= 10; 146 } 147 148 /* Final check */ 149 sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS); 150 if (!(sts & PHY_DPLL_CLK)) { 151 printf("Error:TWL4030:USB Timeout setting PHY DPLL clock\n"); 152 return -1; 153 } 154 155 /* 156 * There are two circuit blocks attached to the PHY, 157 * Carkit and USB OTG. Disable Carkit and enable USB OTG 158 */ 159 twl4030_usb_write(TWL4030_USB_IFC_CTRL_CLR, CARKITMODE); 160 pwr = twl4030_usb_read(TWL4030_USB_POWER_CTRL); 161 pwr |= OTG_ENAB; 162 twl4030_usb_write(TWL4030_USB_POWER_CTRL_SET, pwr); 163 164 /* Clear the opmode bits to ensure normal encode */ 165 twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, OPMODE_MASK); 166 167 /* Clear the xcvrselect bits to enable the high speed transeiver */ 168 twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, XCVRSELECT_MASK); 169 170 /* Let ULPI control the DPLL clock */ 171 clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL); 172 clk &= ~REQ_PHY_DPLL_CLK; 173 twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk); 174 175 return 0; 176 } 177