Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.38-rc2 270 lines 6.3 kB view raw
1/* 2 * Generic ULPI USB transceiver support 3 * 4 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de> 5 * 6 * Based on sources from 7 * 8 * Sascha Hauer <s.hauer@pengutronix.de> 9 * Freescale Semiconductors 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25 26#include <linux/kernel.h> 27#include <linux/slab.h> 28#include <linux/usb.h> 29#include <linux/usb/otg.h> 30#include <linux/usb/ulpi.h> 31 32 33struct ulpi_info { 34 unsigned int id; 35 char *name; 36}; 37 38#define ULPI_ID(vendor, product) (((vendor) << 16) | (product)) 39#define ULPI_INFO(_id, _name) \ 40 { \ 41 .id = (_id), \ 42 .name = (_name), \ 43 } 44 45/* ULPI hardcoded IDs, used for probing */ 46static struct ulpi_info ulpi_ids[] = { 47 ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"), 48 ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB3319"), 49}; 50 51static int ulpi_set_otg_flags(struct otg_transceiver *otg) 52{ 53 unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN | 54 ULPI_OTG_CTRL_DM_PULLDOWN; 55 56 if (otg->flags & ULPI_OTG_ID_PULLUP) 57 flags |= ULPI_OTG_CTRL_ID_PULLUP; 58 59 /* 60 * ULPI Specification rev.1.1 default 61 * for Dp/DmPulldown is enabled. 62 */ 63 if (otg->flags & ULPI_OTG_DP_PULLDOWN_DIS) 64 flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN; 65 66 if (otg->flags & ULPI_OTG_DM_PULLDOWN_DIS) 67 flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN; 68 69 if (otg->flags & ULPI_OTG_EXTVBUSIND) 70 flags |= ULPI_OTG_CTRL_EXTVBUSIND; 71 72 return otg_io_write(otg, flags, ULPI_OTG_CTRL); 73} 74 75static int ulpi_set_fc_flags(struct otg_transceiver *otg) 76{ 77 unsigned int flags = 0; 78 79 /* 80 * ULPI Specification rev.1.1 default 81 * for XcvrSelect is Full Speed. 82 */ 83 if (otg->flags & ULPI_FC_HS) 84 flags |= ULPI_FUNC_CTRL_HIGH_SPEED; 85 else if (otg->flags & ULPI_FC_LS) 86 flags |= ULPI_FUNC_CTRL_LOW_SPEED; 87 else if (otg->flags & ULPI_FC_FS4LS) 88 flags |= ULPI_FUNC_CTRL_FS4LS; 89 else 90 flags |= ULPI_FUNC_CTRL_FULL_SPEED; 91 92 if (otg->flags & ULPI_FC_TERMSEL) 93 flags |= ULPI_FUNC_CTRL_TERMSELECT; 94 95 /* 96 * ULPI Specification rev.1.1 default 97 * for OpMode is Normal Operation. 98 */ 99 if (otg->flags & ULPI_FC_OP_NODRV) 100 flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; 101 else if (otg->flags & ULPI_FC_OP_DIS_NRZI) 102 flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI; 103 else if (otg->flags & ULPI_FC_OP_NSYNC_NEOP) 104 flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP; 105 else 106 flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL; 107 108 /* 109 * ULPI Specification rev.1.1 default 110 * for SuspendM is Powered. 111 */ 112 flags |= ULPI_FUNC_CTRL_SUSPENDM; 113 114 return otg_io_write(otg, flags, ULPI_FUNC_CTRL); 115} 116 117static int ulpi_set_ic_flags(struct otg_transceiver *otg) 118{ 119 unsigned int flags = 0; 120 121 if (otg->flags & ULPI_IC_AUTORESUME) 122 flags |= ULPI_IFC_CTRL_AUTORESUME; 123 124 if (otg->flags & ULPI_IC_EXTVBUS_INDINV) 125 flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS; 126 127 if (otg->flags & ULPI_IC_IND_PASSTHRU) 128 flags |= ULPI_IFC_CTRL_PASSTHRU; 129 130 if (otg->flags & ULPI_IC_PROTECT_DIS) 131 flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE; 132 133 return otg_io_write(otg, flags, ULPI_IFC_CTRL); 134} 135 136static int ulpi_set_flags(struct otg_transceiver *otg) 137{ 138 int ret; 139 140 ret = ulpi_set_otg_flags(otg); 141 if (ret) 142 return ret; 143 144 ret = ulpi_set_ic_flags(otg); 145 if (ret) 146 return ret; 147 148 return ulpi_set_fc_flags(otg); 149} 150 151static int ulpi_check_integrity(struct otg_transceiver *otg) 152{ 153 int ret, i; 154 unsigned int val = 0x55; 155 156 for (i = 0; i < 2; i++) { 157 ret = otg_io_write(otg, val, ULPI_SCRATCH); 158 if (ret < 0) 159 return ret; 160 161 ret = otg_io_read(otg, ULPI_SCRATCH); 162 if (ret < 0) 163 return ret; 164 165 if (ret != val) { 166 pr_err("ULPI integrity check: failed!"); 167 return -ENODEV; 168 } 169 val = val << 1; 170 } 171 172 pr_info("ULPI integrity check: passed.\n"); 173 174 return 0; 175} 176 177static int ulpi_init(struct otg_transceiver *otg) 178{ 179 int i, vid, pid, ret; 180 u32 ulpi_id = 0; 181 182 for (i = 0; i < 4; i++) { 183 ret = otg_io_read(otg, ULPI_PRODUCT_ID_HIGH - i); 184 if (ret < 0) 185 return ret; 186 ulpi_id = (ulpi_id << 8) | ret; 187 } 188 vid = ulpi_id & 0xffff; 189 pid = ulpi_id >> 16; 190 191 pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid); 192 193 for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) { 194 if (ulpi_ids[i].id == ULPI_ID(vid, pid)) { 195 pr_info("Found %s ULPI transceiver.\n", 196 ulpi_ids[i].name); 197 break; 198 } 199 } 200 201 ret = ulpi_check_integrity(otg); 202 if (ret) 203 return ret; 204 205 return ulpi_set_flags(otg); 206} 207 208static int ulpi_set_host(struct otg_transceiver *otg, struct usb_bus *host) 209{ 210 unsigned int flags = otg_io_read(otg, ULPI_IFC_CTRL); 211 212 if (!host) { 213 otg->host = NULL; 214 return 0; 215 } 216 217 otg->host = host; 218 219 flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE | 220 ULPI_IFC_CTRL_3_PIN_SERIAL_MODE | 221 ULPI_IFC_CTRL_CARKITMODE); 222 223 if (otg->flags & ULPI_IC_6PIN_SERIAL) 224 flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE; 225 else if (otg->flags & ULPI_IC_3PIN_SERIAL) 226 flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE; 227 else if (otg->flags & ULPI_IC_CARKIT) 228 flags |= ULPI_IFC_CTRL_CARKITMODE; 229 230 return otg_io_write(otg, flags, ULPI_IFC_CTRL); 231} 232 233static int ulpi_set_vbus(struct otg_transceiver *otg, bool on) 234{ 235 unsigned int flags = otg_io_read(otg, ULPI_OTG_CTRL); 236 237 flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT); 238 239 if (on) { 240 if (otg->flags & ULPI_OTG_DRVVBUS) 241 flags |= ULPI_OTG_CTRL_DRVVBUS; 242 243 if (otg->flags & ULPI_OTG_DRVVBUS_EXT) 244 flags |= ULPI_OTG_CTRL_DRVVBUS_EXT; 245 } 246 247 return otg_io_write(otg, flags, ULPI_OTG_CTRL); 248} 249 250struct otg_transceiver * 251otg_ulpi_create(struct otg_io_access_ops *ops, 252 unsigned int flags) 253{ 254 struct otg_transceiver *otg; 255 256 otg = kzalloc(sizeof(*otg), GFP_KERNEL); 257 if (!otg) 258 return NULL; 259 260 otg->label = "ULPI"; 261 otg->flags = flags; 262 otg->io_ops = ops; 263 otg->init = ulpi_init; 264 otg->set_host = ulpi_set_host; 265 otg->set_vbus = ulpi_set_vbus; 266 267 return otg; 268} 269EXPORT_SYMBOL_GPL(otg_ulpi_create); 270