| 1 | --- /dev/null |
| 2 | +++ b/drivers/usb/host/ehci-fotg2xx.c |
| 3 | @@ -0,0 +1,465 @@ |
| 4 | +/* |
| 5 | + * EHCI Host Controller driver |
| 6 | + * |
| 7 | + * Copyright (C) 2006 Sony Computer Entertainment Inc. |
| 8 | + * Copyright 2006 Sony Corp. |
| 9 | + * |
| 10 | + * This program is free software; you can redistribute it and/or modify |
| 11 | + * it under the terms of the GNU General Public License as published by |
| 12 | + * the Free Software Foundation; version 2 of the License. |
| 13 | + */ |
| 14 | + |
| 15 | +#include <linux/platform_device.h> |
| 16 | +#include <mach/hardware.h> |
| 17 | + |
| 18 | +#define otg_set(port, bits) writel(readl(hcd->regs + port) | bits, hcd->regs + port) |
| 19 | + |
| 20 | +#define otg_clear(port, bits) writel(readl(hcd->regs + port) & ~bits, hcd->regs + port) |
| 21 | + |
| 22 | +#define GLOBAL_ISR 0xC0 |
| 23 | +#define GLOBAL_ICR 0xC4 |
| 24 | + |
| 25 | +#define HCD_MISC 0x40 |
| 26 | + |
| 27 | +#define OTGC_SCR 0x80 |
| 28 | +#define OTGC_INT_EN 0x88 |
| 29 | + |
| 30 | +#define GLOBAL_INT_POLARITY (1 << 3) |
| 31 | +#define GLOBAL_INT_MASK_HC (1 << 2) |
| 32 | +#define GLOBAL_INT_MASK_OTG (1 << 1) |
| 33 | +#define GLOBAL_INT_MASK_DEV (1 << 0) |
| 34 | + |
| 35 | +#define OTGC_SCR_ID (1 << 21) |
| 36 | +#define OTGC_SCR_CROLE (1 << 20) |
| 37 | +#define OTGC_SCR_VBUS_VLD (1 << 19) |
| 38 | +#define OTGC_SCR_A_SRP_RESP_TYPE (1 << 8) |
| 39 | +#define OTGC_SCR_A_SRP_DET_EN (1 << 7) |
| 40 | +#define OTGC_SCR_A_SET_B_HNP_EN (1 << 6) |
| 41 | +#define OTGC_SCR_A_BUS_DROP (1 << 5) |
| 42 | +#define OTGC_SCR_A_BUS_REQ (1 << 4) |
| 43 | + |
| 44 | +#define OTGC_INT_APLGRMV (1 << 12) |
| 45 | +#define OTGC_INT_BPLGRMV (1 << 11) |
| 46 | +#define OTGC_INT_OVC (1 << 10) |
| 47 | +#define OTGC_INT_IDCHG (1 << 9) |
| 48 | +#define OTGC_INT_RLCHG (1 << 8) |
| 49 | +#define OTGC_INT_AVBUSERR (1 << 5) |
| 50 | +#define OTGC_INT_ASRPDET (1 << 4) |
| 51 | +#define OTGC_INT_BSRPDN (1 << 0) |
| 52 | + |
| 53 | +#define OTGC_INT_A_TYPE (OTGC_INT_ASRPDET|OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG|OTGC_INT_APLGRMV) |
| 54 | +#define OTGC_INT_B_TYPE (OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG) |
| 55 | + |
| 56 | +static void fotg2xx_otgc_role_change(struct usb_hcd *hcd); |
| 57 | + |
| 58 | +static void fotg2xx_otgc_init(struct usb_hcd *hcd) |
| 59 | +{ |
| 60 | + struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
| 61 | + unsigned int reg; |
| 62 | + |
| 63 | + reg = __raw_readl(hcd->regs + OTGC_SCR); |
| 64 | + ehci_info(ehci, "role detected: %s, ", |
| 65 | + (reg & OTGC_SCR_CROLE) ? "Peripheral" : "Host"); |
| 66 | + |
| 67 | + if (reg & OTGC_SCR_ID) |
| 68 | + ehci_info(ehci, "B-Device (may be unsupported!)\n"); |
| 69 | + else |
| 70 | + ehci_info(ehci, "A-Device\n"); |
| 71 | + |
| 72 | + /* Enable the SRP detect */ |
| 73 | + reg &= ~OTGC_SCR_A_SRP_RESP_TYPE; |
| 74 | + __raw_writel(reg, hcd->regs + OTGC_SCR); |
| 75 | + |
| 76 | + reg = __raw_readl(hcd->regs + OTGC_INT_EN); |
| 77 | + /* clear INT B: bits AVBUSERR | OVC | RLCHG | IDCHG */ |
| 78 | + reg &= ~OTGC_INT_B_TYPE; |
| 79 | + /* set INT A: bits ASRPDET | AVBUSERR | OVC | RLCHG | IDCHG | APLGRMV */ |
| 80 | + reg |= OTGC_INT_A_TYPE; |
| 81 | + __raw_writel(reg, hcd->regs + OTGC_INT_EN); |
| 82 | + |
| 83 | + reg = __raw_readl(hcd->regs + GLOBAL_ICR); |
| 84 | + reg &= ~GLOBAL_INT_MASK_OTG; |
| 85 | + __raw_writel(reg, hcd->regs + GLOBAL_ICR); |
| 86 | + |
| 87 | + /* setup MISC register, fixes timing problems */ |
| 88 | + reg = __raw_readl(hcd->regs + HCD_MISC); |
| 89 | + reg |= 0xD; |
| 90 | + __raw_writel(reg, hcd->regs + HCD_MISC); |
| 91 | + |
| 92 | + fotg2xx_otgc_role_change(hcd); |
| 93 | +} |
| 94 | + |
| 95 | +static void fotg2xx_otgh_close(struct usb_hcd *hcd) |
| 96 | +{ |
| 97 | + unsigned int reg; |
| 98 | + |
| 99 | + /* <1>.Enable Interrupt Mask */ |
| 100 | + reg = __raw_readl(hcd->regs + GLOBAL_ICR); |
| 101 | + reg |= GLOBAL_INT_MASK_HC; |
| 102 | + __raw_writel(reg, hcd->regs + GLOBAL_ICR); |
| 103 | + |
| 104 | + /* <2>.Clear the Interrupt status */ |
| 105 | + reg = __raw_readl(hcd->regs + 0x18); |
| 106 | + reg &= 0x0000003F; |
| 107 | + __raw_writel(reg, hcd->regs + 0x14); |
| 108 | +} |
| 109 | + |
| 110 | +static void fotg2xx_otgh_open(struct usb_hcd *hcd) |
| 111 | +{ |
| 112 | + unsigned int reg; |
| 113 | + |
| 114 | + reg = __raw_readl(hcd->regs + OTGC_SCR); |
| 115 | + reg &= ~OTGC_SCR_A_SRP_DET_EN; |
| 116 | + __raw_writel(reg, hcd->regs + OTGC_SCR); |
| 117 | + |
| 118 | + reg = __raw_readl(hcd->regs + GLOBAL_ICR); |
| 119 | + reg &= ~GLOBAL_INT_MASK_HC; |
| 120 | + __raw_writel(reg, hcd->regs + GLOBAL_ICR); |
| 121 | +} |
| 122 | + |
| 123 | +/* change to host role */ |
| 124 | +static void fotg2xx_otgc_role_change(struct usb_hcd *hcd) |
| 125 | +{ |
| 126 | + |
| 127 | + /* clear A_SET_B_HNP_EN */ |
| 128 | + otg_clear(0x80, BIT(6)); |
| 129 | + |
| 130 | + /*** Enable VBUS driving */ |
| 131 | + if (readl(hcd->regs + 0x80) & BIT(19)) |
| 132 | + printk(KERN_INFO "VBUS already enabled\n"); |
| 133 | + else { |
| 134 | + int cnt = 0; |
| 135 | + |
| 136 | + /* clear A_BUS_DROP */ |
| 137 | + otg_clear(0x80, BIT(5)); |
| 138 | + |
| 139 | + /* set A_BUS_REQ */ |
| 140 | + otg_set(0x80, BIT(4)); |
| 141 | + |
| 142 | + /* set global bus reg to VBUS on */ |
| 143 | + writel(readl(IO_ADDRESS(0x40000000) + 0x30) | ((BIT(21)|BIT(22))), |
| 144 | + IO_ADDRESS(0x40000000) + 0x30); |
| 145 | + |
| 146 | + if (readl(hcd->regs + 0x80) & (1<<19)) { |
| 147 | + printk(KERN_INFO "Waiting for VBus"); |
| 148 | + while (!(readl(hcd->regs + 0x80) & (1<<19)) && (cnt < 80)) { |
| 149 | + printk(KERN_CONT "."); |
| 150 | + cnt++; |
| 151 | + } |
| 152 | + printk(KERN_CONT "\n"); |
| 153 | + } else |
| 154 | + printk(KERN_INFO "VBUS enabled.\n"); |
| 155 | + |
| 156 | + mdelay(1); |
| 157 | + } |
| 158 | + fotg2xx_otgh_open(hcd); |
| 159 | +} |
| 160 | + |
| 161 | +static int fotg2xx_ehci_hc_reset(struct usb_hcd *hcd) |
| 162 | +{ |
| 163 | + int result; |
| 164 | + struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
| 165 | + |
| 166 | + ehci->caps = hcd->regs; |
| 167 | + ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); |
| 168 | + |
| 169 | + dbg_hcs_params(ehci, "reset"); |
| 170 | + dbg_hcc_params(ehci, "reset"); |
| 171 | + |
| 172 | + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
| 173 | + hcd->has_tt = 1; |
| 174 | + |
| 175 | + result = ehci_halt(ehci); |
| 176 | + if (result) |
| 177 | + return result; |
| 178 | + |
| 179 | + result = ehci_init(hcd); |
| 180 | + if (result) |
| 181 | + return result; |
| 182 | + |
| 183 | + ehci_port_power(ehci, 0); |
| 184 | + |
| 185 | + return result; |
| 186 | +} |
| 187 | + |
| 188 | +/* |
| 189 | + * Name: OTGC_INT_ISR |
| 190 | + * Description:This interrupt service routine belongs to the OTG-Controller |
| 191 | + * <1>.Check for ID_Change |
| 192 | + * <2>.Check for RL_Change |
| 193 | + * <3>.Error Detect |
| 194 | + * Input: wINTStatus |
| 195 | + * Output:void |
| 196 | + */ |
| 197 | +void fotg2xx_int_isr(struct usb_hcd *hcd, u32 wINTStatus) |
| 198 | +{ |
| 199 | + /* <1>.Check for ID_Change */ |
| 200 | + if (wINTStatus&OTGC_INT_IDCHG) { |
| 201 | + if ((readl(hcd->regs + 0x80) & BIT(21)) != 0) |
| 202 | + fotg2xx_otgc_init(hcd); /* Change to B Type */ |
| 203 | + else |
| 204 | + fotg2xx_otgc_init(hcd); /* Change to A Type */ |
| 205 | + |
| 206 | + return; |
| 207 | + } |
| 208 | + |
| 209 | + /* <2>.Check for RL_Change */ |
| 210 | + if (wINTStatus&OTGC_INT_RLCHG) |
| 211 | + fotg2xx_otgc_role_change(hcd); |
| 212 | + |
| 213 | + /* <3>.Error Detect */ |
| 214 | + if (wINTStatus&OTGC_INT_AVBUSERR) |
| 215 | + printk(KERN_ERR "VBus error!\n"); |
| 216 | + |
| 217 | + if (wINTStatus&OTGC_INT_OVC) |
| 218 | + printk(KERN_WARNING "Overcurrent detected!\n"); |
| 219 | + |
| 220 | + /* <3>.Check for Type-A/Type-B Interrupt */ |
| 221 | + if ((readl(hcd->regs + 0x80) & BIT(21)) == 0) { /*For Type-A Interrupt*/ |
| 222 | + if (wINTStatus & (OTGC_INT_A_TYPE | OTGC_INT_ASRPDET)) { |
| 223 | + /* <1>.SRP detected => then set global variable */ |
| 224 | + printk(KERN_WARNING "SRP detected, but not implemented!\n"); |
| 225 | + |
| 226 | +#if 0 |
| 227 | + u32 wTempCounter; |
| 228 | + /* <2>.Turn on the V Bus */ |
| 229 | + pFTC_OTG->otg.state = OTG_STATE_A_WAIT_VRISE; |
| 230 | + OTGC_enable_vbus_draw_storlink(1); |
| 231 | + pFTC_OTG->otg.state = OTG_STATE_A_HOST; |
| 232 | + /* <3>.Should waiting for Device-Connect Wait 300ms */ |
| 233 | + INFO(pFTC_OTG, ">>> OTG-A Waiting for OTG-B Connect,\n"); |
| 234 | + wTempCounter = 0; |
| 235 | + while (mwHost20_PORTSC_ConnectStatus_Rd() == 0) { |
| 236 | + mdelay(1); |
| 237 | + wTempCounter++; |
| 238 | + /* Waiting for 300 ms */ |
| 239 | + if (wTempCounter > 300) { |
| 240 | + mdwOTGC_Control_A_SRP_DET_EN_Clr(); |
| 241 | + INFO(pFTC_OTG, ">>> OTG-B do not connect under 300 ms...\n"); |
| 242 | + break; |
| 243 | + } |
| 244 | + } |
| 245 | + /* <4>.If Connect => issue quick Reset */ |
| 246 | + if (mwHost20_PORTSC_ConnectStatus_Rd() > 0) { |
| 247 | + mdelay(300); /* For OPT-A Test */ |
| 248 | + OTGH_host_quick_Reset(); |
| 249 | + OTGH_Open(); |
| 250 | + pFTC_OTG->otg.host->A_Disable_Set_Feature_HNP = 0; |
| 251 | + } |
| 252 | +#endif |
| 253 | + } |
| 254 | + } else { /* For Type-B Interrupt */ |
| 255 | + BUG(); |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +static irqreturn_t fotg2xx_ehci_irq(int irq, void *devid) |
| 260 | +{ |
| 261 | + struct usb_hcd *hcd = devid; |
| 262 | + u32 val; |
| 263 | + |
| 264 | + /* OTG Interrupt Status Register */ |
| 265 | + val = readl(hcd->regs + 0x84); |
| 266 | + |
| 267 | + /* OTG stuff */ |
| 268 | + if (val) { |
| 269 | + /* supposed to do "INT STS Clr" - XXX */ |
| 270 | + writel(readl(hcd->regs + 0x84) | val, hcd->regs + 0x84); |
| 271 | + |
| 272 | + fotg2xx_int_isr(hcd, val); |
| 273 | + |
| 274 | + /* supposed to do "INT STS Clr" - XXX */ |
| 275 | + writel(readl(hcd->regs + 0x84) | val, hcd->regs + 0x84); |
| 276 | + |
| 277 | + return IRQ_HANDLED; |
| 278 | + } |
| 279 | + |
| 280 | + if ((readl(hcd->regs + 0x80) & BIT(20)) == 0) { /* Role is HOST */ |
| 281 | + if (readl(hcd->regs + 0xC0) & BIT(2)) { /* INT STS HOST */ |
| 282 | + /* leave this for ehci irq handler */ |
| 283 | + return IRQ_NONE; |
| 284 | + } |
| 285 | + } else |
| 286 | + printk(KERN_WARNING |
| 287 | + "received irq for peripheral - don't know what to do!\n"); |
| 288 | + |
| 289 | + /* do not call the ehci irq handler */ |
| 290 | + return IRQ_HANDLED; |
| 291 | +} |
| 292 | + |
| 293 | +static int fotg2xx_ehci_run(struct usb_hcd *hcd) |
| 294 | +{ |
| 295 | + int retval; |
| 296 | + |
| 297 | + retval = ehci_run(hcd); |
| 298 | + |
| 299 | + fotg2xx_otgh_close(hcd); |
| 300 | + fotg2xx_otgc_init(hcd); |
| 301 | + |
| 302 | + return retval; |
| 303 | +} |
| 304 | + |
| 305 | +static const struct hc_driver fotg2xx_ehci_hc_driver = { |
| 306 | + .description = hcd_name, |
| 307 | + .product_desc = "FOTG2XX EHCI Host Controller", |
| 308 | + .hcd_priv_size = sizeof(struct ehci_hcd), |
| 309 | + .irq = ehci_irq, |
| 310 | + .flags = HCD_MEMORY | HCD_USB2, |
| 311 | + .reset = fotg2xx_ehci_hc_reset, |
| 312 | + .start = fotg2xx_ehci_run, |
| 313 | + .stop = ehci_stop, |
| 314 | + .shutdown = ehci_shutdown, |
| 315 | + |
| 316 | + .urb_enqueue = ehci_urb_enqueue, |
| 317 | + .urb_dequeue = ehci_urb_dequeue, |
| 318 | + .endpoint_disable = ehci_endpoint_disable, |
| 319 | + .endpoint_reset = ehci_endpoint_reset, |
| 320 | + |
| 321 | + .get_frame_number = ehci_get_frame, |
| 322 | + |
| 323 | + .hub_status_data = ehci_hub_status_data, |
| 324 | + .hub_control = ehci_hub_control, |
| 325 | +#if defined(CONFIG_PM) |
| 326 | + .bus_suspend = ehci_bus_suspend, |
| 327 | + .bus_resume = ehci_bus_resume, |
| 328 | +#endif |
| 329 | + .relinquish_port = ehci_relinquish_port, |
| 330 | + .port_handed_over = ehci_port_handed_over, |
| 331 | + |
| 332 | + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
| 333 | +}; |
| 334 | + |
| 335 | +static int fotg2xx_ehci_probe(struct platform_device *pdev) |
| 336 | +{ |
| 337 | + const struct hc_driver *driver = &fotg2xx_ehci_hc_driver; |
| 338 | + struct usb_hcd *hcd; |
| 339 | + struct resource *res; |
| 340 | + int irq; |
| 341 | + int retval; |
| 342 | + |
| 343 | + pr_debug("initializing FOTG2XX-SOC USB Controller\n"); |
| 344 | + |
| 345 | + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 346 | + if (!res) { |
| 347 | + dev_err(&pdev->dev, |
| 348 | + "Found HC with no IRQ. Check %s setup!\n", |
| 349 | + dev_name(&pdev->dev)); |
| 350 | + return -ENODEV; |
| 351 | + } |
| 352 | + |
| 353 | + irq = res->start; |
| 354 | + |
| 355 | + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); |
| 356 | + if (!hcd) { |
| 357 | + retval = -ENOMEM; |
| 358 | + goto err1; |
| 359 | + } |
| 360 | + |
| 361 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 362 | + if (!res) { |
| 363 | + dev_err(&pdev->dev, |
| 364 | + "Found HC with no register addr. Check %s setup!\n", |
| 365 | + dev_name(&pdev->dev)); |
| 366 | + retval = -ENODEV; |
| 367 | + goto err2; |
| 368 | + } |
| 369 | + |
| 370 | + hcd->rsrc_start = res->start; |
| 371 | + hcd->rsrc_len = res->end - res->start + 1; |
| 372 | + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, |
| 373 | + driver->description)) { |
| 374 | + dev_dbg(&pdev->dev, "controller already in use\n"); |
| 375 | + retval = -EBUSY; |
| 376 | + goto err2; |
| 377 | + } |
| 378 | + |
| 379 | + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); |
| 380 | + if (hcd->regs == NULL) { |
| 381 | + dev_dbg(&pdev->dev, "error mapping memory\n"); |
| 382 | + retval = -EFAULT; |
| 383 | + goto err3; |
| 384 | + } |
| 385 | + |
| 386 | + |
| 387 | + /* set global reg to mini-A host */ |
| 388 | + writel(readl(IO_ADDRESS(0x40000000) + 0x30) & ~(BIT(30)|BIT(29)), |
| 389 | + IO_ADDRESS(0x40000000) + 0x30); |
| 390 | + |
| 391 | + /* USB0&USB1 - VBUS off */ |
| 392 | + writel(readl(IO_ADDRESS(0x40000000) + 0x30) & ~(BIT(21)|BIT(22)), |
| 393 | + IO_ADDRESS(0x40000000) + 0x30); |
| 394 | + |
| 395 | + if ((readl(hcd->regs) == 0x01000010) && |
| 396 | + (readl(hcd->regs + 4) == 0x00000001) && |
| 397 | + (readl(hcd->regs + 8) == 0x00000006)) { |
| 398 | + dev_info(&pdev->dev, |
| 399 | + "Found Faraday OTG 2XX controller (base = 0x%08lX)\n", |
| 400 | + (unsigned long) hcd->rsrc_start); |
| 401 | + } else { |
| 402 | + dev_err(&pdev->dev, "fotg2xx id mismatch: found %d.%d.%d\n", |
| 403 | + readl(hcd->regs + 0x00), |
| 404 | + readl(hcd->regs + 0x04), |
| 405 | + readl(hcd->regs + 0x08)); |
| 406 | + retval = -ENODEV; |
| 407 | + goto err4; |
| 408 | + } |
| 409 | + |
| 410 | + platform_set_drvdata(pdev, hcd); |
| 411 | + |
| 412 | + /* mask interrupts - peripheral, otg, host, hi-active (bits 0,1,2,3) */ |
| 413 | + otg_set(0xc4, BIT(3)); /* hi active */ |
| 414 | + |
| 415 | + otg_set(0xc4, BIT(2)); /* host */ |
| 416 | + otg_set(0xc4, BIT(1)); /* otg */ |
| 417 | + otg_set(0xc4, BIT(0)); /* peripheral */ |
| 418 | + |
| 419 | + /* register additional interrupt - here we check otg status */ |
| 420 | + if ((request_irq(irq, &fotg2xx_ehci_irq, IRQF_SHARED | IRQF_DISABLED, |
| 421 | + hcd->irq_descr, hcd)) != 0) { |
| 422 | + dev_dbg(&pdev->dev, "error requesting irq %d\n", irq); |
| 423 | + retval = -EFAULT; |
| 424 | + goto err4; |
| 425 | + } |
| 426 | + |
| 427 | + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); |
| 428 | + if (retval != 0) |
| 429 | + goto err4; |
| 430 | + return retval; |
| 431 | + |
| 432 | +err4: |
| 433 | + iounmap(hcd->regs); |
| 434 | +err3: |
| 435 | + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
| 436 | +err2: |
| 437 | + usb_put_hcd(hcd); |
| 438 | +err1: |
| 439 | + dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); |
| 440 | + return retval; |
| 441 | +} |
| 442 | + |
| 443 | +/* may be called without controller electrically present */ |
| 444 | +/* may be called with controller, bus, and devices active */ |
| 445 | + |
| 446 | +int fotg2xx_ehci_remove(struct platform_device *pdev) |
| 447 | +{ |
| 448 | + struct usb_hcd *hcd = |
| 449 | + (struct usb_hcd *)platform_get_drvdata(pdev); |
| 450 | + |
| 451 | + usb_remove_hcd(hcd); |
| 452 | + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
| 453 | + iounmap(hcd->regs); |
| 454 | + usb_put_hcd(hcd); |
| 455 | + platform_set_drvdata(pdev, NULL); |
| 456 | + |
| 457 | + return 0; |
| 458 | +} |
| 459 | + |
| 460 | +MODULE_ALIAS("platform:ehci-fotg2xx"); |
| 461 | + |
| 462 | +static struct platform_driver fotg2xx_ehci_driver = { |
| 463 | + .probe = fotg2xx_ehci_probe, |
| 464 | + .remove = fotg2xx_ehci_remove, |
| 465 | + .driver = { |
| 466 | + .name = "ehci-fotg2xx", |
| 467 | + }, |
| 468 | +}; |
| 469 | --- a/drivers/usb/host/ehci.h |
| 470 | +++ b/drivers/usb/host/ehci.h |
| 471 | @@ -581,7 +581,12 @@ static inline unsigned int |
| 472 | ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) |
| 473 | { |
| 474 | if (ehci_is_TDI(ehci)) { |
| 475 | +#ifdef CONFIG_ARCH_GEMINI |
| 476 | + portsc = readl(ehci_to_hcd(ehci)->regs + 0x80); |
| 477 | + switch ((portsc>>22)&3) { |
| 478 | +#else |
| 479 | switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) { |
| 480 | +#endif |
| 481 | case 0: |
| 482 | return 0; |
| 483 | case 1: |
| 484 | --- a/drivers/usb/host/ehci-hcd.c |
| 485 | +++ b/drivers/usb/host/ehci-hcd.c |
| 486 | @@ -227,9 +227,11 @@ static int ehci_halt (struct ehci_hcd *e |
| 487 | if ((temp & STS_HALT) != 0) |
| 488 | return 0; |
| 489 | |
| 490 | +#ifndef CONFIG_ARCH_GEMINI |
| 491 | temp = ehci_readl(ehci, &ehci->regs->command); |
| 492 | temp &= ~CMD_RUN; |
| 493 | ehci_writel(ehci, temp, &ehci->regs->command); |
| 494 | +#endif |
| 495 | return handshake (ehci, &ehci->regs->status, |
| 496 | STS_HALT, STS_HALT, 16 * 125); |
| 497 | } |
| 498 | @@ -342,8 +344,10 @@ static int ehci_reset (struct ehci_hcd * |
| 499 | if (retval) |
| 500 | return retval; |
| 501 | |
| 502 | +#ifndef CONFIG_ARCH_GEMINI |
| 503 | if (ehci_is_TDI(ehci)) |
| 504 | tdi_reset (ehci); |
| 505 | +#endif |
| 506 | |
| 507 | if (ehci->debug) |
| 508 | dbgp_external_startup(); |
| 509 | @@ -478,12 +482,13 @@ static void ehci_silence_controller(stru |
| 510 | { |
| 511 | ehci_halt(ehci); |
| 512 | ehci_turn_off_all_ports(ehci); |
| 513 | - |
| 514 | +#ifndef CONFIG_ARCH_GEMINI |
| 515 | /* make BIOS/etc use companion controller during reboot */ |
| 516 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); |
| 517 | |
| 518 | /* unblock posted writes */ |
| 519 | ehci_readl(ehci, &ehci->regs->configured_flag); |
| 520 | +#endif |
| 521 | } |
| 522 | |
| 523 | /* ehci_shutdown kick in for silicon on any bus (not just pci, etc). |
| 524 | @@ -764,7 +769,9 @@ static int ehci_run (struct usb_hcd *hcd |
| 525 | // Philips, Intel, and maybe others need CMD_RUN before the |
| 526 | // root hub will detect new devices (why?); NEC doesn't |
| 527 | ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); |
| 528 | +#ifndef CONFIG_ARCH_GEMINI |
| 529 | ehci->command |= CMD_RUN; |
| 530 | +#endif |
| 531 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
| 532 | dbg_cmd (ehci, "init", ehci->command); |
| 533 | |
| 534 | @@ -784,9 +791,11 @@ static int ehci_run (struct usb_hcd *hcd |
| 535 | */ |
| 536 | down_write(&ehci_cf_port_reset_rwsem); |
| 537 | ehci->rh_state = EHCI_RH_RUNNING; |
| 538 | +#ifndef CONFIG_ARCH_GEMINI |
| 539 | ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); |
| 540 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ |
| 541 | msleep(5); |
| 542 | +#endif /* !CONFIG_ARCH_GEMINI */ |
| 543 | up_write(&ehci_cf_port_reset_rwsem); |
| 544 | ehci->last_periodic_enable = ktime_get_real(); |
| 545 | |
| 546 | @@ -958,7 +967,9 @@ static irqreturn_t ehci_irq (struct usb_ |
| 547 | ehci_halt(ehci); |
| 548 | dead: |
| 549 | ehci_reset(ehci); |
| 550 | +#ifndef CONFIG_ARCH_GEMINI |
| 551 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); |
| 552 | +#endif |
| 553 | usb_hc_died(hcd); |
| 554 | /* generic layer kills/unlinks all urbs, then |
| 555 | * uses ehci_stop to clean up the rest |
| 556 | @@ -1256,6 +1267,11 @@ MODULE_LICENSE ("GPL"); |
| 557 | #define PCI_DRIVER ehci_pci_driver |
| 558 | #endif |
| 559 | |
| 560 | +#ifdef CONFIG_ARCH_GEMINI |
| 561 | +#include "ehci-fotg2xx.c" |
| 562 | +#define PLATFORM_DRIVER fotg2xx_ehci_driver |
| 563 | +#endif |
| 564 | + |
| 565 | #ifdef CONFIG_USB_EHCI_FSL |
| 566 | #include "ehci-fsl.c" |
| 567 | #define PLATFORM_DRIVER ehci_fsl_driver |
| 568 | --- a/drivers/usb/host/ehci-hub.c |
| 569 | +++ b/drivers/usb/host/ehci-hub.c |
| 570 | @@ -882,6 +882,12 @@ static int ehci_hub_control ( |
| 571 | /* see what we found out */ |
| 572 | temp = check_reset_complete (ehci, wIndex, status_reg, |
| 573 | ehci_readl(ehci, status_reg)); |
| 574 | +#ifdef CONFIG_ARCH_GEMINI |
| 575 | + /* restart schedule */ |
| 576 | + ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) | CMD_RUN, &ehci->regs->command); |
| 577 | + |
| 578 | +// hcd->state = HC_STATE_RUNNING; |
| 579 | +#endif |
| 580 | } |
| 581 | |
| 582 | if (!(temp & (PORT_RESUME|PORT_RESET))) |
| 583 | --- a/drivers/usb/Kconfig |
| 584 | +++ b/drivers/usb/Kconfig |
| 585 | @@ -76,6 +76,7 @@ config USB_ARCH_HAS_EHCI |
| 586 | default y if MICROBLAZE |
| 587 | default y if SPARC_LEON |
| 588 | default y if ARCH_MMP |
| 589 | + default y if ARCH_GEMINI |
| 590 | default PCI |
| 591 | |
| 592 | # some non-PCI HCDs implement xHCI |
| 593 | @@ -94,7 +95,7 @@ config USB |
| 594 | traditional PC serial port. The bus supplies power to peripherals |
| 595 | and allows for hot swapping. Up to 127 USB peripherals can be |
| 596 | connected to a single USB host in a tree structure. |
| 597 | - |
| 598 | + |
| 599 | The USB host is the root of the tree, the peripherals are the |
| 600 | leaves and the inner nodes are special USB devices called hubs. |
| 601 | Most PCs now have USB host ports, used to connect peripherals |
| 602 | --- a/include/linux/usb/ehci_def.h |
| 603 | +++ b/include/linux/usb/ehci_def.h |
| 604 | @@ -110,9 +110,9 @@ struct ehci_regs { |
| 605 | u32 frame_list; /* points to periodic list */ |
| 606 | /* ASYNCLISTADDR: offset 0x18 */ |
| 607 | u32 async_next; /* address of next async queue head */ |
| 608 | - |
| 609 | +#ifndef CONFIG_ARCH_GEMINI |
| 610 | u32 reserved[9]; |
| 611 | - |
| 612 | +#endif |
| 613 | /* CONFIGFLAG: offset 0x40 */ |
| 614 | u32 configured_flag; |
| 615 | #define FLAG_CF (1<<0) /* true: we'll support "high speed" */ |
| 616 | |