1 /* 2 * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com> 3 * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il> 4 * 5 * Authors: Jana Rapava <fermata7@gmail.com> 6 * Igor Grinberg <grinberg@compulab.co.il> 7 * 8 * Based on: 9 * linux/drivers/usb/otg/ulpi.c 10 * Generic ULPI USB transceiver support 11 * 12 * Original Copyright follow: 13 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de> 14 * 15 * Based on sources from 16 * 17 * Sascha Hauer <s.hauer@pengutronix.de> 18 * Freescale Semiconductors 19 * 20 * This program is free software; you can redistribute it and/or modify 21 * it under the terms of the GNU General Public License as published by 22 * the Free Software Foundation; either version 2 of the License, or 23 * (at your option) any later version. 24 * 25 * This program is distributed in the hope that it will be useful, 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * GNU General Public License for more details. 29 */ 30 31 #include <common.h> 32 #include <exports.h> 33 #include <usb/ulpi.h> 34 35 #define ULPI_ID_REGS_COUNT 4 36 #define ULPI_TEST_VALUE 0x55 /* 0x55 == 0b01010101 */ 37 38 static struct ulpi_regs *ulpi = (struct ulpi_regs *)0; 39 40 static int ulpi_integrity_check(u32 ulpi_viewport) 41 { 42 u32 val, tval = ULPI_TEST_VALUE; 43 int err, i; 44 45 /* Use the 'special' test value to check all bits */ 46 for (i = 0; i < 2; i++, tval <<= 1) { 47 err = ulpi_write(ulpi_viewport, &ulpi->scratch, tval); 48 if (err) 49 return err; 50 51 val = ulpi_read(ulpi_viewport, &ulpi->scratch); 52 if (val != tval) { 53 printf("ULPI integrity check failed\n"); 54 return val; 55 } 56 } 57 58 return 0; 59 } 60 61 int ulpi_init(u32 ulpi_viewport) 62 { 63 u32 val, id = 0; 64 u8 *reg = &ulpi->product_id_high; 65 int i; 66 67 /* Assemble ID from four ULPI ID registers (8 bits each). */ 68 for (i = 0; i < ULPI_ID_REGS_COUNT; i++) { 69 val = ulpi_read(ulpi_viewport, reg - i); 70 if (val == ULPI_ERROR) 71 return val; 72 73 id = (id << 8) | val; 74 } 75 76 /* Split ID into vendor and product ID. */ 77 debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff); 78 79 return ulpi_integrity_check(ulpi_viewport); 80 } 81 82 int ulpi_select_transceiver(u32 ulpi_viewport, unsigned speed) 83 { 84 u32 tspeed = ULPI_FC_FULL_SPEED; 85 u32 val; 86 87 switch (speed) { 88 case ULPI_FC_HIGH_SPEED: 89 case ULPI_FC_FULL_SPEED: 90 case ULPI_FC_LOW_SPEED: 91 case ULPI_FC_FS4LS: 92 tspeed = speed; 93 break; 94 default: 95 printf("ULPI: %s: wrong transceiver speed specified: %u, " 96 "falling back to full speed\n", __func__, speed); 97 } 98 99 val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl); 100 if (val == ULPI_ERROR) 101 return val; 102 103 /* clear the previous speed setting */ 104 val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed; 105 106 return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val); 107 } 108 109 int ulpi_set_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind) 110 { 111 u32 flags = ULPI_OTG_DRVVBUS; 112 u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; 113 114 if (ext_power) 115 flags |= ULPI_OTG_DRVVBUS_EXT; 116 if (ext_ind) 117 flags |= ULPI_OTG_EXTVBUSIND; 118 119 return ulpi_write(ulpi_viewport, reg, flags); 120 } 121 122 int ulpi_set_pd(u32 ulpi_viewport, int enable) 123 { 124 u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN; 125 u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; 126 127 return ulpi_write(ulpi_viewport, reg, val); 128 } 129 130 int ulpi_opmode_sel(u32 ulpi_viewport, unsigned opmode) 131 { 132 u32 topmode = ULPI_FC_OPMODE_NORMAL; 133 u32 val; 134 135 switch (opmode) { 136 case ULPI_FC_OPMODE_NORMAL: 137 case ULPI_FC_OPMODE_NONDRIVING: 138 case ULPI_FC_OPMODE_DISABLE_NRZI: 139 case ULPI_FC_OPMODE_NOSYNC_NOEOP: 140 topmode = opmode; 141 break; 142 default: 143 printf("ULPI: %s: wrong OpMode specified: %u, " 144 "falling back to OpMode Normal\n", __func__, opmode); 145 } 146 147 val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl); 148 if (val == ULPI_ERROR) 149 return val; 150 151 /* clear the previous opmode setting */ 152 val = (val & ~ULPI_FC_OPMODE_MASK) | topmode; 153 154 return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val); 155 } 156 157 int ulpi_serial_mode_enable(u32 ulpi_viewport, unsigned smode) 158 { 159 switch (smode) { 160 case ULPI_IFACE_6_PIN_SERIAL_MODE: 161 case ULPI_IFACE_3_PIN_SERIAL_MODE: 162 break; 163 default: 164 printf("ULPI: %s: unrecognized Serial Mode specified: %u\n", 165 __func__, smode); 166 return ULPI_ERROR; 167 } 168 169 return ulpi_write(ulpi_viewport, &ulpi->iface_ctrl_set, smode); 170 } 171 172 int ulpi_suspend(u32 ulpi_viewport) 173 { 174 int err; 175 176 err = ulpi_write(ulpi_viewport, &ulpi->function_ctrl_clear, 177 ULPI_FC_SUSPENDM); 178 if (err) 179 printf("ULPI: %s: failed writing the suspend bit\n", __func__); 180 181 return err; 182 } 183 184 /* 185 * Wait for ULPI PHY reset to complete. 186 * Actual wait for reset must be done in a view port specific way, 187 * because it involves checking the DIR line. 188 */ 189 static int __ulpi_reset_wait(u32 ulpi_viewport) 190 { 191 u32 val; 192 int timeout = CONFIG_USB_ULPI_TIMEOUT; 193 194 /* Wait for the RESET bit to become zero */ 195 while (--timeout) { 196 /* 197 * This function is generic and suppose to work 198 * with any viewport, so we cheat here and don't check 199 * for the error of ulpi_read(), if there is one, then 200 * there will be a timeout. 201 */ 202 val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl); 203 if (!(val & ULPI_FC_RESET)) 204 return 0; 205 206 udelay(1); 207 } 208 209 printf("ULPI: %s: reset timed out\n", __func__); 210 211 return ULPI_ERROR; 212 } 213 int ulpi_reset_wait(u32) __attribute__((weak, alias("__ulpi_reset_wait"))); 214 215 int ulpi_reset(u32 ulpi_viewport) 216 { 217 int err; 218 219 err = ulpi_write(ulpi_viewport, 220 &ulpi->function_ctrl_set, ULPI_FC_RESET); 221 if (err) { 222 printf("ULPI: %s: failed writing reset bit\n", __func__); 223 return err; 224 } 225 226 return ulpi_reset_wait(ulpi_viewport); 227 } 228