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