| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * arch/arm/mach-omap/usb.c -- platform level USB initialization | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2004 Texas Instruments, Inc. | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or modify | 
|  | 7 | * it under the terms of the GNU General Public License as published by | 
|  | 8 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 9 | * (at your option) any later version. | 
|  | 10 | * | 
|  | 11 | * This program is distributed in the hope that it will be useful, | 
|  | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 14 | * GNU General Public License for more details. | 
|  | 15 | * | 
|  | 16 | * You should have received a copy of the GNU General Public License | 
|  | 17 | * along with this program; if not, write to the Free Software | 
|  | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | 19 | */ | 
|  | 20 |  | 
|  | 21 | #undef	DEBUG | 
|  | 22 |  | 
|  | 23 | #include <linux/config.h> | 
|  | 24 | #include <linux/module.h> | 
|  | 25 | #include <linux/kernel.h> | 
|  | 26 | #include <linux/types.h> | 
|  | 27 | #include <linux/errno.h> | 
|  | 28 | #include <linux/init.h> | 
|  | 29 | #include <linux/device.h> | 
|  | 30 | #include <linux/usb_otg.h> | 
|  | 31 |  | 
|  | 32 | #include <asm/io.h> | 
|  | 33 | #include <asm/irq.h> | 
|  | 34 | #include <asm/system.h> | 
|  | 35 | #include <asm/hardware.h> | 
|  | 36 | #include <asm/mach-types.h> | 
|  | 37 |  | 
|  | 38 | #include <asm/arch/mux.h> | 
|  | 39 | #include <asm/arch/usb.h> | 
|  | 40 | #include <asm/arch/board.h> | 
|  | 41 |  | 
|  | 42 | /* These routines should handle the standard chip-specific modes | 
|  | 43 | * for usb0/1/2 ports, covering basic mux and transceiver setup. | 
|  | 44 | * Call omap_usb_init() once, from INIT_MACHINE(). | 
|  | 45 | * | 
|  | 46 | * Some board-*.c files will need to set up additional mux options, | 
|  | 47 | * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. | 
|  | 48 | */ | 
|  | 49 |  | 
|  | 50 | /* TESTED ON: | 
|  | 51 | *  - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables | 
|  | 52 | *  - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables | 
|  | 53 | *  - 5912 OSK UDC, with *nonstandard* A-to-A cable | 
|  | 54 | *  - 1510 Innovator UDC with bundled usb0 cable | 
|  | 55 | *  - 1510 Innovator OHCI with bundled usb1/usb2 cable | 
|  | 56 | *  - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS | 
|  | 57 | *  - 1710 custom development board using alternate pin group | 
|  | 58 | *  - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables | 
|  | 59 | */ | 
|  | 60 |  | 
|  | 61 | /*-------------------------------------------------------------------------*/ | 
|  | 62 |  | 
|  | 63 | #ifdef	CONFIG_ARCH_OMAP_OTG | 
|  | 64 |  | 
|  | 65 | static struct otg_transceiver *xceiv; | 
|  | 66 |  | 
|  | 67 | /** | 
|  | 68 | * otg_get_transceiver - find the (single) OTG transceiver driver | 
|  | 69 | * | 
|  | 70 | * Returns the transceiver driver, after getting a refcount to it; or | 
|  | 71 | * null if there is no such transceiver.  The caller is responsible for | 
|  | 72 | * releasing that count. | 
|  | 73 | */ | 
|  | 74 | struct otg_transceiver *otg_get_transceiver(void) | 
|  | 75 | { | 
|  | 76 | if (xceiv) | 
|  | 77 | get_device(xceiv->dev); | 
|  | 78 | return xceiv; | 
|  | 79 | } | 
|  | 80 | EXPORT_SYMBOL(otg_get_transceiver); | 
|  | 81 |  | 
|  | 82 | int otg_set_transceiver(struct otg_transceiver *x) | 
|  | 83 | { | 
|  | 84 | if (xceiv && x) | 
|  | 85 | return -EBUSY; | 
|  | 86 | xceiv = x; | 
|  | 87 | return 0; | 
|  | 88 | } | 
|  | 89 | EXPORT_SYMBOL(otg_set_transceiver); | 
|  | 90 |  | 
|  | 91 | #endif | 
|  | 92 |  | 
|  | 93 | /*-------------------------------------------------------------------------*/ | 
|  | 94 |  | 
|  | 95 | static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) | 
|  | 96 | { | 
|  | 97 | u32	syscon1 = 0; | 
|  | 98 |  | 
|  | 99 | if (nwires == 0) { | 
|  | 100 | if (!cpu_is_omap15xx()) { | 
|  | 101 | /* pulldown D+/D- */ | 
|  | 102 | USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1); | 
|  | 103 | } | 
|  | 104 | return 0; | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | if (is_device) | 
|  | 108 | omap_cfg_reg(W4_USB_PUEN); | 
|  | 109 |  | 
|  | 110 | /* internal transceiver */ | 
|  | 111 | if (nwires == 2) { | 
|  | 112 | // omap_cfg_reg(P9_USB_DP); | 
|  | 113 | // omap_cfg_reg(R8_USB_DM); | 
|  | 114 |  | 
|  | 115 | if (cpu_is_omap15xx()) { | 
|  | 116 | /* This works on 1510-Innovator */ | 
|  | 117 | return 0; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | /* NOTES: | 
|  | 121 | *  - peripheral should configure VBUS detection! | 
|  | 122 | *  - only peripherals may use the internal D+/D- pulldowns | 
|  | 123 | *  - OTG support on this port not yet written | 
|  | 124 | */ | 
|  | 125 |  | 
|  | 126 | USB_TRANSCEIVER_CTRL_REG &= ~(7 << 4); | 
|  | 127 | if (!is_device) | 
|  | 128 | USB_TRANSCEIVER_CTRL_REG |= (3 << 1); | 
|  | 129 |  | 
|  | 130 | return 3 << 16; | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | /* alternate pin config, external transceiver */ | 
|  | 134 | if (cpu_is_omap15xx()) { | 
|  | 135 | printk(KERN_ERR "no usb0 alt pin config on 15xx\n"); | 
|  | 136 | return 0; | 
|  | 137 | } | 
|  | 138 |  | 
|  | 139 | omap_cfg_reg(V6_USB0_TXD); | 
|  | 140 | omap_cfg_reg(W9_USB0_TXEN); | 
|  | 141 | omap_cfg_reg(W5_USB0_SE0); | 
|  | 142 |  | 
|  | 143 | /* NOTE:  SPEED and SUSP aren't configured here */ | 
|  | 144 |  | 
|  | 145 | if (nwires != 3) | 
|  | 146 | omap_cfg_reg(Y5_USB0_RCV); | 
|  | 147 | if (nwires != 6) | 
|  | 148 | USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; | 
|  | 149 |  | 
|  | 150 | switch (nwires) { | 
|  | 151 | case 3: | 
|  | 152 | syscon1 = 2; | 
|  | 153 | break; | 
|  | 154 | case 4: | 
|  | 155 | syscon1 = 1; | 
|  | 156 | break; | 
|  | 157 | case 6: | 
|  | 158 | syscon1 = 3; | 
|  | 159 | omap_cfg_reg(AA9_USB0_VP); | 
|  | 160 | omap_cfg_reg(R9_USB0_VM); | 
|  | 161 | USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; | 
|  | 162 | break; | 
|  | 163 | default: | 
|  | 164 | printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", | 
|  | 165 | 0, nwires); | 
|  | 166 | } | 
|  | 167 | return syscon1 << 16; | 
|  | 168 | } | 
|  | 169 |  | 
|  | 170 | static u32 __init omap_usb1_init(unsigned nwires) | 
|  | 171 | { | 
|  | 172 | u32	syscon1 = 0; | 
|  | 173 |  | 
|  | 174 | if (nwires != 6 && !cpu_is_omap15xx()) | 
|  | 175 | USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R; | 
|  | 176 | if (nwires == 0) | 
|  | 177 | return 0; | 
|  | 178 |  | 
|  | 179 | /* external transceiver */ | 
|  | 180 | omap_cfg_reg(USB1_TXD); | 
|  | 181 | omap_cfg_reg(USB1_TXEN); | 
|  | 182 | if (cpu_is_omap15xx()) { | 
|  | 183 | omap_cfg_reg(USB1_SEO); | 
|  | 184 | omap_cfg_reg(USB1_SPEED); | 
|  | 185 | // SUSP | 
|  | 186 | } else if (cpu_is_omap1610() || cpu_is_omap5912()) { | 
|  | 187 | omap_cfg_reg(W13_1610_USB1_SE0); | 
|  | 188 | omap_cfg_reg(R13_1610_USB1_SPEED); | 
|  | 189 | // SUSP | 
|  | 190 | } else if (cpu_is_omap1710()) { | 
|  | 191 | omap_cfg_reg(R13_1710_USB1_SE0); | 
|  | 192 | // SUSP | 
|  | 193 | } else { | 
|  | 194 | pr_debug("usb unrecognized\n"); | 
|  | 195 | } | 
|  | 196 | if (nwires != 3) | 
|  | 197 | omap_cfg_reg(USB1_RCV); | 
|  | 198 |  | 
|  | 199 | switch (nwires) { | 
|  | 200 | case 3: | 
|  | 201 | syscon1 = 2; | 
|  | 202 | break; | 
|  | 203 | case 4: | 
|  | 204 | syscon1 = 1; | 
|  | 205 | break; | 
|  | 206 | case 6: | 
|  | 207 | syscon1 = 3; | 
|  | 208 | omap_cfg_reg(USB1_VP); | 
|  | 209 | omap_cfg_reg(USB1_VM); | 
|  | 210 | if (!cpu_is_omap15xx()) | 
|  | 211 | USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R; | 
|  | 212 | break; | 
|  | 213 | default: | 
|  | 214 | printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", | 
|  | 215 | 1, nwires); | 
|  | 216 | } | 
|  | 217 | return syscon1 << 20; | 
|  | 218 | } | 
|  | 219 |  | 
|  | 220 | static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) | 
|  | 221 | { | 
|  | 222 | u32	syscon1 = 0; | 
|  | 223 |  | 
|  | 224 | /* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */ | 
|  | 225 | if (alt_pingroup || nwires == 0) | 
|  | 226 | return 0; | 
|  | 227 | if (nwires != 6 && !cpu_is_omap15xx()) | 
|  | 228 | USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; | 
|  | 229 |  | 
|  | 230 | /* external transceiver */ | 
|  | 231 | if (cpu_is_omap15xx()) { | 
|  | 232 | omap_cfg_reg(USB2_TXD); | 
|  | 233 | omap_cfg_reg(USB2_TXEN); | 
|  | 234 | omap_cfg_reg(USB2_SEO); | 
|  | 235 | if (nwires != 3) | 
|  | 236 | omap_cfg_reg(USB2_RCV); | 
|  | 237 | /* there is no USB2_SPEED */ | 
|  | 238 | } else if (cpu_is_omap16xx()) { | 
|  | 239 | omap_cfg_reg(V6_USB2_TXD); | 
|  | 240 | omap_cfg_reg(W9_USB2_TXEN); | 
|  | 241 | omap_cfg_reg(W5_USB2_SE0); | 
|  | 242 | if (nwires != 3) | 
|  | 243 | omap_cfg_reg(Y5_USB2_RCV); | 
|  | 244 | // FIXME omap_cfg_reg(USB2_SPEED); | 
|  | 245 | } else { | 
|  | 246 | pr_debug("usb unrecognized\n"); | 
|  | 247 | } | 
|  | 248 | // omap_cfg_reg(USB2_SUSP); | 
|  | 249 |  | 
|  | 250 | switch (nwires) { | 
|  | 251 | case 3: | 
|  | 252 | syscon1 = 2; | 
|  | 253 | break; | 
|  | 254 | case 4: | 
|  | 255 | syscon1 = 1; | 
|  | 256 | break; | 
|  | 257 | case 6: | 
|  | 258 | syscon1 = 3; | 
|  | 259 | if (cpu_is_omap15xx()) { | 
|  | 260 | omap_cfg_reg(USB2_VP); | 
|  | 261 | omap_cfg_reg(USB2_VM); | 
|  | 262 | } else { | 
|  | 263 | omap_cfg_reg(AA9_USB2_VP); | 
|  | 264 | omap_cfg_reg(R9_USB2_VM); | 
|  | 265 | USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; | 
|  | 266 | } | 
|  | 267 | break; | 
|  | 268 | default: | 
|  | 269 | printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", | 
|  | 270 | 2, nwires); | 
|  | 271 | } | 
|  | 272 | return syscon1 << 24; | 
|  | 273 | } | 
|  | 274 |  | 
|  | 275 | /*-------------------------------------------------------------------------*/ | 
|  | 276 |  | 
|  | 277 | #if	defined(CONFIG_USB_GADGET_OMAP) || \ | 
|  | 278 | defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \ | 
|  | 279 | (defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)) | 
|  | 280 | static void usb_release(struct device *dev) | 
|  | 281 | { | 
|  | 282 | /* normally not freed */ | 
|  | 283 | } | 
|  | 284 | #endif | 
|  | 285 |  | 
|  | 286 | #ifdef	CONFIG_USB_GADGET_OMAP | 
|  | 287 |  | 
|  | 288 | static struct resource udc_resources[] = { | 
|  | 289 | /* order is significant! */ | 
|  | 290 | {		/* registers */ | 
|  | 291 | .start		= IO_ADDRESS(UDC_BASE), | 
|  | 292 | .end		= IO_ADDRESS(UDC_BASE + 0xff), | 
|  | 293 | .flags		= IORESOURCE_MEM, | 
|  | 294 | }, {		/* general IRQ */ | 
|  | 295 | .start		= IH2_BASE + 20, | 
|  | 296 | .flags		= IORESOURCE_IRQ, | 
|  | 297 | }, {		/* PIO IRQ */ | 
|  | 298 | .start		= IH2_BASE + 30, | 
|  | 299 | .flags		= IORESOURCE_IRQ, | 
|  | 300 | }, {		/* SOF IRQ */ | 
|  | 301 | .start		= IH2_BASE + 29, | 
|  | 302 | .flags		= IORESOURCE_IRQ, | 
|  | 303 | }, | 
|  | 304 | }; | 
|  | 305 |  | 
|  | 306 | static u64 udc_dmamask = ~(u32)0; | 
|  | 307 |  | 
|  | 308 | static struct platform_device udc_device = { | 
|  | 309 | .name		= "omap_udc", | 
|  | 310 | .id		= -1, | 
|  | 311 | .dev = { | 
|  | 312 | .release		= usb_release, | 
|  | 313 | .dma_mask		= &udc_dmamask, | 
|  | 314 | .coherent_dma_mask	= 0xffffffff, | 
|  | 315 | }, | 
|  | 316 | .num_resources	= ARRAY_SIZE(udc_resources), | 
|  | 317 | .resource	= udc_resources, | 
|  | 318 | }; | 
|  | 319 |  | 
|  | 320 | #endif | 
|  | 321 |  | 
|  | 322 | #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) | 
|  | 323 |  | 
|  | 324 | /* The dmamask must be set for OHCI to work */ | 
|  | 325 | static u64 ohci_dmamask = ~(u32)0; | 
|  | 326 |  | 
|  | 327 | static struct resource ohci_resources[] = { | 
|  | 328 | { | 
|  | 329 | .start	= OMAP_OHCI_BASE, | 
|  | 330 | .end	= OMAP_OHCI_BASE + 4096, | 
|  | 331 | .flags	= IORESOURCE_MEM, | 
|  | 332 | }, | 
|  | 333 | { | 
|  | 334 | .start	= INT_USB_HHC_1, | 
|  | 335 | .flags	= IORESOURCE_IRQ, | 
|  | 336 | }, | 
|  | 337 | }; | 
|  | 338 |  | 
|  | 339 | static struct platform_device ohci_device = { | 
|  | 340 | .name			= "ohci", | 
|  | 341 | .id			= -1, | 
|  | 342 | .dev = { | 
|  | 343 | .release		= usb_release, | 
|  | 344 | .dma_mask		= &ohci_dmamask, | 
|  | 345 | .coherent_dma_mask	= 0xffffffff, | 
|  | 346 | }, | 
|  | 347 | .num_resources	= ARRAY_SIZE(ohci_resources), | 
|  | 348 | .resource		= ohci_resources, | 
|  | 349 | }; | 
|  | 350 |  | 
|  | 351 | #endif | 
|  | 352 |  | 
|  | 353 | #if	defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG) | 
|  | 354 |  | 
|  | 355 | static struct resource otg_resources[] = { | 
|  | 356 | /* order is significant! */ | 
|  | 357 | { | 
|  | 358 | .start		= IO_ADDRESS(OTG_BASE), | 
|  | 359 | .end		= IO_ADDRESS(OTG_BASE + 0xff), | 
|  | 360 | .flags		= IORESOURCE_MEM, | 
|  | 361 | }, { | 
|  | 362 | .start		= IH2_BASE + 8, | 
|  | 363 | .flags		= IORESOURCE_IRQ, | 
|  | 364 | }, | 
|  | 365 | }; | 
|  | 366 |  | 
|  | 367 | static struct platform_device otg_device = { | 
|  | 368 | .name		= "omap_otg", | 
|  | 369 | .id		= -1, | 
|  | 370 | .dev = { | 
|  | 371 | .release		= usb_release, | 
|  | 372 | }, | 
|  | 373 | .num_resources	= ARRAY_SIZE(otg_resources), | 
|  | 374 | .resource	= otg_resources, | 
|  | 375 | }; | 
|  | 376 |  | 
|  | 377 | #endif | 
|  | 378 |  | 
|  | 379 | /*-------------------------------------------------------------------------*/ | 
|  | 380 |  | 
|  | 381 | #define ULPD_CLOCK_CTRL_REG	__REG16(ULPD_CLOCK_CTRL) | 
|  | 382 | #define ULPD_SOFT_REQ_REG	__REG16(ULPD_SOFT_REQ) | 
|  | 383 |  | 
|  | 384 |  | 
|  | 385 | // FIXME correct answer depends on hmc_mode, | 
|  | 386 | // as does any nonzero value for config->otg port number | 
|  | 387 | #ifdef	CONFIG_USB_GADGET_OMAP | 
|  | 388 | #define	is_usb0_device(config)	1 | 
|  | 389 | #else | 
|  | 390 | #define	is_usb0_device(config)	0 | 
|  | 391 | #endif | 
|  | 392 |  | 
|  | 393 | /*-------------------------------------------------------------------------*/ | 
|  | 394 |  | 
|  | 395 | #ifdef	CONFIG_ARCH_OMAP_OTG | 
|  | 396 |  | 
|  | 397 | void __init | 
|  | 398 | omap_otg_init(struct omap_usb_config *config) | 
|  | 399 | { | 
|  | 400 | u32		syscon = OTG_SYSCON_1_REG & 0xffff; | 
|  | 401 | int		status; | 
|  | 402 | int		alt_pingroup = 0; | 
|  | 403 |  | 
|  | 404 | /* NOTE:  no bus or clock setup (yet?) */ | 
|  | 405 |  | 
|  | 406 | syscon = OTG_SYSCON_1_REG & 0xffff; | 
|  | 407 | if (!(syscon & OTG_RESET_DONE)) | 
|  | 408 | pr_debug("USB resets not complete?\n"); | 
|  | 409 |  | 
|  | 410 | // OTG_IRQ_EN_REG = 0; | 
|  | 411 |  | 
|  | 412 | /* pin muxing and transceiver pinouts */ | 
|  | 413 | if (config->pins[0] > 2)	/* alt pingroup 2 */ | 
|  | 414 | alt_pingroup = 1; | 
|  | 415 | syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config)); | 
|  | 416 | syscon |= omap_usb1_init(config->pins[1]); | 
|  | 417 | syscon |= omap_usb2_init(config->pins[2], alt_pingroup); | 
|  | 418 | pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); | 
|  | 419 | OTG_SYSCON_1_REG = syscon; | 
|  | 420 |  | 
|  | 421 | syscon = config->hmc_mode; | 
|  | 422 | syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */; | 
|  | 423 | #ifdef	CONFIG_USB_OTG | 
|  | 424 | if (config->otg) | 
|  | 425 | syscon |= OTG_EN; | 
|  | 426 | #endif | 
|  | 427 | pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG); | 
|  | 428 | pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon); | 
|  | 429 | OTG_SYSCON_2_REG = syscon; | 
|  | 430 |  | 
|  | 431 | printk("USB: hmc %d", config->hmc_mode); | 
|  | 432 | if (alt_pingroup) | 
|  | 433 | printk(", usb2 alt %d wires", config->pins[2]); | 
|  | 434 | else if (config->pins[0]) | 
|  | 435 | printk(", usb0 %d wires%s", config->pins[0], | 
|  | 436 | is_usb0_device(config) ? " (dev)" : ""); | 
|  | 437 | if (config->pins[1]) | 
|  | 438 | printk(", usb1 %d wires", config->pins[1]); | 
|  | 439 | if (!alt_pingroup && config->pins[2]) | 
|  | 440 | printk(", usb2 %d wires", config->pins[2]); | 
|  | 441 | if (config->otg) | 
|  | 442 | printk(", Mini-AB on usb%d", config->otg - 1); | 
|  | 443 | printk("\n"); | 
|  | 444 |  | 
|  | 445 | /* leave USB clocks/controllers off until needed */ | 
|  | 446 | ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ; | 
|  | 447 | ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN; | 
|  | 448 | ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK; | 
|  | 449 | syscon = OTG_SYSCON_1_REG; | 
|  | 450 | syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN; | 
|  | 451 |  | 
|  | 452 | #ifdef	CONFIG_USB_GADGET_OMAP | 
|  | 453 | if (config->otg || config->register_dev) { | 
|  | 454 | syscon &= ~DEV_IDLE_EN; | 
|  | 455 | udc_device.dev.platform_data = config; | 
|  | 456 | /* FIXME patch IRQ numbers for omap730 */ | 
|  | 457 | status = platform_device_register(&udc_device); | 
|  | 458 | if (status) | 
|  | 459 | pr_debug("can't register UDC device, %d\n", status); | 
|  | 460 | } | 
|  | 461 | #endif | 
|  | 462 |  | 
|  | 463 | #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) | 
|  | 464 | if (config->otg || config->register_host) { | 
|  | 465 | syscon &= ~HST_IDLE_EN; | 
|  | 466 | ohci_device.dev.platform_data = config; | 
|  | 467 | if (cpu_is_omap730()) | 
|  | 468 | ohci_resources[1].start = INT_730_USB_HHC_1; | 
|  | 469 | status = platform_device_register(&ohci_device); | 
|  | 470 | if (status) | 
|  | 471 | pr_debug("can't register OHCI device, %d\n", status); | 
|  | 472 | } | 
|  | 473 | #endif | 
|  | 474 |  | 
|  | 475 | #ifdef	CONFIG_USB_OTG | 
|  | 476 | if (config->otg) { | 
|  | 477 | syscon &= ~OTG_IDLE_EN; | 
|  | 478 | otg_device.dev.platform_data = config; | 
|  | 479 | if (cpu_is_omap730()) | 
|  | 480 | otg_resources[1].start = INT_730_USB_OTG; | 
|  | 481 | status = platform_device_register(&otg_device); | 
|  | 482 | if (status) | 
|  | 483 | pr_debug("can't register OTG device, %d\n", status); | 
|  | 484 | } | 
|  | 485 | #endif | 
|  | 486 | pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); | 
|  | 487 | OTG_SYSCON_1_REG = syscon; | 
|  | 488 |  | 
|  | 489 | status = 0; | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | #else | 
|  | 493 | static inline void omap_otg_init(struct omap_usb_config *config) {} | 
|  | 494 | #endif | 
|  | 495 |  | 
|  | 496 | /*-------------------------------------------------------------------------*/ | 
|  | 497 |  | 
|  | 498 | #ifdef	CONFIG_ARCH_OMAP1510 | 
|  | 499 |  | 
|  | 500 | #define ULPD_DPLL_CTRL_REG	__REG16(ULPD_DPLL_CTRL) | 
|  | 501 | #define DPLL_IOB		(1 << 13) | 
|  | 502 | #define DPLL_PLL_ENABLE		(1 << 4) | 
|  | 503 | #define DPLL_LOCK		(1 << 0) | 
|  | 504 |  | 
|  | 505 | #define ULPD_APLL_CTRL_REG	__REG16(ULPD_APLL_CTRL) | 
|  | 506 | #define APLL_NDPLL_SWITCH	(1 << 0) | 
|  | 507 |  | 
|  | 508 |  | 
|  | 509 | static void __init omap_1510_usb_init(struct omap_usb_config *config) | 
|  | 510 | { | 
|  | 511 | int status; | 
|  | 512 | unsigned int val; | 
|  | 513 |  | 
|  | 514 | omap_usb0_init(config->pins[0], is_usb0_device(config)); | 
|  | 515 | omap_usb1_init(config->pins[1]); | 
|  | 516 | omap_usb2_init(config->pins[2], 0); | 
|  | 517 |  | 
|  | 518 | val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1); | 
|  | 519 | val |= (config->hmc_mode << 1); | 
|  | 520 | omap_writel(val, MOD_CONF_CTRL_0); | 
|  | 521 |  | 
|  | 522 | printk("USB: hmc %d", config->hmc_mode); | 
|  | 523 | if (config->pins[0]) | 
|  | 524 | printk(", usb0 %d wires%s", config->pins[0], | 
|  | 525 | is_usb0_device(config) ? " (dev)" : ""); | 
|  | 526 | if (config->pins[1]) | 
|  | 527 | printk(", usb1 %d wires", config->pins[1]); | 
|  | 528 | if (config->pins[2]) | 
|  | 529 | printk(", usb2 %d wires", config->pins[2]); | 
|  | 530 | printk("\n"); | 
|  | 531 |  | 
|  | 532 | /* use DPLL for 48 MHz function clock */ | 
|  | 533 | pr_debug("APLL %04x DPLL %04x REQ %04x\n", ULPD_APLL_CTRL_REG, | 
|  | 534 | ULPD_DPLL_CTRL_REG, ULPD_SOFT_REQ_REG); | 
|  | 535 | ULPD_APLL_CTRL_REG &= ~APLL_NDPLL_SWITCH; | 
|  | 536 | ULPD_DPLL_CTRL_REG |= DPLL_IOB | DPLL_PLL_ENABLE; | 
|  | 537 | ULPD_SOFT_REQ_REG |= SOFT_UDC_REQ | SOFT_DPLL_REQ; | 
|  | 538 | while (!(ULPD_DPLL_CTRL_REG & DPLL_LOCK)) | 
|  | 539 | cpu_relax(); | 
|  | 540 |  | 
|  | 541 | #ifdef	CONFIG_USB_GADGET_OMAP | 
|  | 542 | if (config->register_dev) { | 
|  | 543 | udc_device.dev.platform_data = config; | 
|  | 544 | status = platform_device_register(&udc_device); | 
|  | 545 | if (status) | 
|  | 546 | pr_debug("can't register UDC device, %d\n", status); | 
|  | 547 | /* udc driver gates 48MHz by D+ pullup */ | 
|  | 548 | } | 
|  | 549 | #endif | 
|  | 550 |  | 
|  | 551 | #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) | 
|  | 552 | if (config->register_host) { | 
|  | 553 | ohci_device.dev.platform_data = config; | 
|  | 554 | status = platform_device_register(&ohci_device); | 
|  | 555 | if (status) | 
|  | 556 | pr_debug("can't register OHCI device, %d\n", status); | 
|  | 557 | /* hcd explicitly gates 48MHz */ | 
|  | 558 | } | 
|  | 559 | #endif | 
|  | 560 | } | 
|  | 561 |  | 
|  | 562 | #else | 
|  | 563 | static inline void omap_1510_usb_init(struct omap_usb_config *config) {} | 
|  | 564 | #endif | 
|  | 565 |  | 
|  | 566 | /*-------------------------------------------------------------------------*/ | 
|  | 567 |  | 
|  | 568 | static struct omap_usb_config platform_data; | 
|  | 569 |  | 
|  | 570 | static int __init | 
|  | 571 | omap_usb_init(void) | 
|  | 572 | { | 
|  | 573 | const struct omap_usb_config *config; | 
|  | 574 |  | 
|  | 575 | config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config); | 
|  | 576 | if (config == NULL) { | 
|  | 577 | printk(KERN_ERR "USB: No board-specific " | 
|  | 578 | "platform config found\n"); | 
|  | 579 | return -ENODEV; | 
|  | 580 | } | 
|  | 581 | platform_data = *config; | 
|  | 582 |  | 
|  | 583 | if (cpu_is_omap730() || cpu_is_omap16xx()) | 
|  | 584 | omap_otg_init(&platform_data); | 
|  | 585 | else if (cpu_is_omap15xx()) | 
|  | 586 | omap_1510_usb_init(&platform_data); | 
|  | 587 | else { | 
|  | 588 | printk(KERN_ERR "USB: No init for your chip yet\n"); | 
|  | 589 | return -ENODEV; | 
|  | 590 | } | 
|  | 591 | return 0; | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | subsys_initcall(omap_usb_init); |