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(struct ulpi_viewport *ulpi_vp) 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_vp, &ulpi->scratch, tval); 48 if (err) 49 return err; 50 51 val = ulpi_read(ulpi_vp, &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(struct ulpi_viewport *ulpi_vp) 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_vp, 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_vp); 80 } 81 82 int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, 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_vp, &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_vp, &ulpi->function_ctrl, val); 107 } 108 109 int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power, 110 int ext_ind) 111 { 112 u32 flags = ULPI_OTG_DRVVBUS; 113 u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; 114 115 if (ext_power) 116 flags |= ULPI_OTG_DRVVBUS_EXT; 117 if (ext_ind) 118 flags |= ULPI_OTG_EXTVBUSIND; 119 120 return ulpi_write(ulpi_vp, reg, flags); 121 } 122 123 int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable) 124 { 125 u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN; 126 u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; 127 128 return ulpi_write(ulpi_vp, reg, val); 129 } 130 131 int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode) 132 { 133 u32 topmode = ULPI_FC_OPMODE_NORMAL; 134 u32 val; 135 136 switch (opmode) { 137 case ULPI_FC_OPMODE_NORMAL: 138 case ULPI_FC_OPMODE_NONDRIVING: 139 case ULPI_FC_OPMODE_DISABLE_NRZI: 140 case ULPI_FC_OPMODE_NOSYNC_NOEOP: 141 topmode = opmode; 142 break; 143 default: 144 printf("ULPI: %s: wrong OpMode specified: %u, " 145 "falling back to OpMode Normal\n", __func__, opmode); 146 } 147 148 val = ulpi_read(ulpi_vp, &ulpi->function_ctrl); 149 if (val == ULPI_ERROR) 150 return val; 151 152 /* clear the previous opmode setting */ 153 val = (val & ~ULPI_FC_OPMODE_MASK) | topmode; 154 155 return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val); 156 } 157 158 int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode) 159 { 160 switch (smode) { 161 case ULPI_IFACE_6_PIN_SERIAL_MODE: 162 case ULPI_IFACE_3_PIN_SERIAL_MODE: 163 break; 164 default: 165 printf("ULPI: %s: unrecognized Serial Mode specified: %u\n", 166 __func__, smode); 167 return ULPI_ERROR; 168 } 169 170 return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode); 171 } 172 173 int ulpi_suspend(struct ulpi_viewport *ulpi_vp) 174 { 175 int err; 176 177 err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear, 178 ULPI_FC_SUSPENDM); 179 if (err) 180 printf("ULPI: %s: failed writing the suspend bit\n", __func__); 181 182 return err; 183 } 184 185 /* 186 * Wait for ULPI PHY reset to complete. 187 * Actual wait for reset must be done in a view port specific way, 188 * because it involves checking the DIR line. 189 */ 190 static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp) 191 { 192 u32 val; 193 int timeout = CONFIG_USB_ULPI_TIMEOUT; 194 195 /* Wait for the RESET bit to become zero */ 196 while (--timeout) { 197 /* 198 * This function is generic and suppose to work 199 * with any viewport, so we cheat here and don't check 200 * for the error of ulpi_read(), if there is one, then 201 * there will be a timeout. 202 */ 203 val = ulpi_read(ulpi_vp, &ulpi->function_ctrl); 204 if (!(val & ULPI_FC_RESET)) 205 return 0; 206 207 udelay(1); 208 } 209 210 printf("ULPI: %s: reset timed out\n", __func__); 211 212 return ULPI_ERROR; 213 } 214 int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp) 215 __attribute__((weak, alias("__ulpi_reset_wait"))); 216 217 int ulpi_reset(struct ulpi_viewport *ulpi_vp) 218 { 219 int err; 220 221 err = ulpi_write(ulpi_vp, 222 &ulpi->function_ctrl_set, ULPI_FC_RESET); 223 if (err) { 224 printf("ULPI: %s: failed writing reset bit\n", __func__); 225 return err; 226 } 227 228 return ulpi_reset_wait(ulpi_vp); 229 } 230