musb_virthub.c revision 69ae2a70bfabbd6af6309bf723ec76493512dba1
1/* 2 * MUSB OTG driver virtual root hub support 3 * 4 * Copyright 2005 Mentor Graphics Corporation 5 * Copyright (C) 2005-2006 by Texas Instruments 6 * Copyright (C) 2006-2007 Nokia Corporation 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 * 22 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 25 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35#include <linux/module.h> 36#include <linux/kernel.h> 37#include <linux/sched.h> 38#include <linux/errno.h> 39#include <linux/init.h> 40#include <linux/time.h> 41#include <linux/timer.h> 42 43#include <asm/unaligned.h> 44 45#include "musb_core.h" 46 47/* 48* Program the HDRC to start (enable interrupts, dma, etc.). 49*/ 50static void musb_start(struct musb *musb) 51{ 52 void __iomem *regs = musb->mregs; 53 u8 devctl = musb_readb(regs, MUSB_DEVCTL); 54 55 dev_dbg(musb->controller, "<== devctl %02x\n", devctl); 56 57 /* Set INT enable registers, enable interrupts */ 58 musb->intrtxe = musb->epmask; 59 musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); 60 musb->intrrxe = musb->epmask & 0xfffe; 61 musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); 62 musb_writeb(regs, MUSB_INTRUSBE, 0xf7); 63 64 musb_writeb(regs, MUSB_TESTMODE, 0); 65 66 /* put into basic highspeed mode and start session */ 67 musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE 68 | MUSB_POWER_HSENAB 69 /* ENSUSPEND wedges tusb */ 70 /* | MUSB_POWER_ENSUSPEND */ 71 ); 72 73 musb->is_active = 0; 74 devctl = musb_readb(regs, MUSB_DEVCTL); 75 devctl &= ~MUSB_DEVCTL_SESSION; 76 77 /* session started after: 78 * (a) ID-grounded irq, host mode; 79 * (b) vbus present/connect IRQ, peripheral mode; 80 * (c) peripheral initiates, using SRP 81 */ 82 if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { 83 musb->is_active = 1; 84 } else { 85 devctl |= MUSB_DEVCTL_SESSION; 86 } 87 88 musb_platform_enable(musb); 89 musb_writeb(regs, MUSB_DEVCTL, devctl); 90} 91 92static void musb_port_suspend(struct musb *musb, bool do_suspend) 93{ 94 struct usb_otg *otg = musb->xceiv->otg; 95 u8 power; 96 void __iomem *mbase = musb->mregs; 97 98 if (!is_host_active(musb)) 99 return; 100 101 /* NOTE: this doesn't necessarily put PHY into low power mode, 102 * turning off its clock; that's a function of PHY integration and 103 * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect 104 * SE0 changing to connect (J) or wakeup (K) states. 105 */ 106 power = musb_readb(mbase, MUSB_POWER); 107 if (do_suspend) { 108 int retries = 10000; 109 110 power &= ~MUSB_POWER_RESUME; 111 power |= MUSB_POWER_SUSPENDM; 112 musb_writeb(mbase, MUSB_POWER, power); 113 114 /* Needed for OPT A tests */ 115 power = musb_readb(mbase, MUSB_POWER); 116 while (power & MUSB_POWER_SUSPENDM) { 117 power = musb_readb(mbase, MUSB_POWER); 118 if (retries-- < 1) 119 break; 120 } 121 122 dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); 123 124 musb->port1_status |= USB_PORT_STAT_SUSPEND; 125 switch (musb->xceiv->state) { 126 case OTG_STATE_A_HOST: 127 musb->xceiv->state = OTG_STATE_A_SUSPEND; 128 musb->is_active = otg->host->b_hnp_enable; 129 if (musb->is_active) 130 mod_timer(&musb->otg_timer, jiffies 131 + msecs_to_jiffies( 132 OTG_TIME_A_AIDL_BDIS)); 133 musb_platform_try_idle(musb, 0); 134 break; 135 case OTG_STATE_B_HOST: 136 musb->xceiv->state = OTG_STATE_B_WAIT_ACON; 137 musb->is_active = otg->host->b_hnp_enable; 138 musb_platform_try_idle(musb, 0); 139 break; 140 default: 141 dev_dbg(musb->controller, "bogus rh suspend? %s\n", 142 usb_otg_state_string(musb->xceiv->state)); 143 } 144 } else if (power & MUSB_POWER_SUSPENDM) { 145 power &= ~MUSB_POWER_SUSPENDM; 146 power |= MUSB_POWER_RESUME; 147 musb_writeb(mbase, MUSB_POWER, power); 148 149 dev_dbg(musb->controller, "Root port resuming, power %02x\n", power); 150 151 /* later, GetPortStatus will stop RESUME signaling */ 152 musb->port1_status |= MUSB_PORT_STAT_RESUME; 153 musb->rh_timer = jiffies + msecs_to_jiffies(20); 154 } 155} 156 157static void musb_port_reset(struct musb *musb, bool do_reset) 158{ 159 u8 power; 160 void __iomem *mbase = musb->mregs; 161 162 if (musb->xceiv->state == OTG_STATE_B_IDLE) { 163 dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); 164 musb->port1_status &= ~USB_PORT_STAT_RESET; 165 return; 166 } 167 168 if (!is_host_active(musb)) 169 return; 170 171 /* NOTE: caller guarantees it will turn off the reset when 172 * the appropriate amount of time has passed 173 */ 174 power = musb_readb(mbase, MUSB_POWER); 175 if (do_reset) { 176 177 /* 178 * If RESUME is set, we must make sure it stays minimum 20 ms. 179 * Then we must clear RESUME and wait a bit to let musb start 180 * generating SOFs. If we don't do this, OPT HS A 6.8 tests 181 * fail with "Error! Did not receive an SOF before suspend 182 * detected". 183 */ 184 if (power & MUSB_POWER_RESUME) { 185 while (time_before(jiffies, musb->rh_timer)) 186 msleep(1); 187 musb_writeb(mbase, MUSB_POWER, 188 power & ~MUSB_POWER_RESUME); 189 msleep(1); 190 } 191 192 power &= 0xf0; 193 musb_writeb(mbase, MUSB_POWER, 194 power | MUSB_POWER_RESET); 195 196 musb->port1_status |= USB_PORT_STAT_RESET; 197 musb->port1_status &= ~USB_PORT_STAT_ENABLE; 198 musb->rh_timer = jiffies + msecs_to_jiffies(50); 199 } else { 200 dev_dbg(musb->controller, "root port reset stopped\n"); 201 musb_writeb(mbase, MUSB_POWER, 202 power & ~MUSB_POWER_RESET); 203 204 power = musb_readb(mbase, MUSB_POWER); 205 if (power & MUSB_POWER_HSMODE) { 206 dev_dbg(musb->controller, "high-speed device connected\n"); 207 musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; 208 } 209 210 musb->port1_status &= ~USB_PORT_STAT_RESET; 211 musb->port1_status |= USB_PORT_STAT_ENABLE 212 | (USB_PORT_STAT_C_RESET << 16) 213 | (USB_PORT_STAT_C_ENABLE << 16); 214 usb_hcd_poll_rh_status(musb_to_hcd(musb)); 215 216 musb->vbuserr_retry = VBUSERR_RETRY_COUNT; 217 } 218} 219 220void musb_root_disconnect(struct musb *musb) 221{ 222 struct usb_otg *otg = musb->xceiv->otg; 223 224 musb->port1_status = USB_PORT_STAT_POWER 225 | (USB_PORT_STAT_C_CONNECTION << 16); 226 227 usb_hcd_poll_rh_status(musb_to_hcd(musb)); 228 musb->is_active = 0; 229 230 switch (musb->xceiv->state) { 231 case OTG_STATE_A_SUSPEND: 232 if (otg->host->b_hnp_enable) { 233 musb->xceiv->state = OTG_STATE_A_PERIPHERAL; 234 musb->g.is_a_peripheral = 1; 235 break; 236 } 237 /* FALLTHROUGH */ 238 case OTG_STATE_A_HOST: 239 musb->xceiv->state = OTG_STATE_A_WAIT_BCON; 240 musb->is_active = 0; 241 break; 242 case OTG_STATE_A_WAIT_VFALL: 243 musb->xceiv->state = OTG_STATE_B_IDLE; 244 break; 245 default: 246 dev_dbg(musb->controller, "host disconnect (%s)\n", 247 usb_otg_state_string(musb->xceiv->state)); 248 } 249} 250 251 252/*---------------------------------------------------------------------*/ 253 254/* Caller may or may not hold musb->lock */ 255int musb_hub_status_data(struct usb_hcd *hcd, char *buf) 256{ 257 struct musb *musb = hcd_to_musb(hcd); 258 int retval = 0; 259 260 /* called in_irq() via usb_hcd_poll_rh_status() */ 261 if (musb->port1_status & 0xffff0000) { 262 *buf = 0x02; 263 retval = 1; 264 } 265 return retval; 266} 267 268int musb_hub_control( 269 struct usb_hcd *hcd, 270 u16 typeReq, 271 u16 wValue, 272 u16 wIndex, 273 char *buf, 274 u16 wLength) 275{ 276 struct musb *musb = hcd_to_musb(hcd); 277 u32 temp; 278 int retval = 0; 279 unsigned long flags; 280 281 spin_lock_irqsave(&musb->lock, flags); 282 283 if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) { 284 spin_unlock_irqrestore(&musb->lock, flags); 285 return -ESHUTDOWN; 286 } 287 288 /* hub features: always zero, setting is a NOP 289 * port features: reported, sometimes updated when host is active 290 * no indicators 291 */ 292 switch (typeReq) { 293 case ClearHubFeature: 294 case SetHubFeature: 295 switch (wValue) { 296 case C_HUB_OVER_CURRENT: 297 case C_HUB_LOCAL_POWER: 298 break; 299 default: 300 goto error; 301 } 302 break; 303 case ClearPortFeature: 304 if ((wIndex & 0xff) != 1) 305 goto error; 306 307 switch (wValue) { 308 case USB_PORT_FEAT_ENABLE: 309 break; 310 case USB_PORT_FEAT_SUSPEND: 311 musb_port_suspend(musb, false); 312 break; 313 case USB_PORT_FEAT_POWER: 314 if (!hcd->self.is_b_host) 315 musb_platform_set_vbus(musb, 0); 316 break; 317 case USB_PORT_FEAT_C_CONNECTION: 318 case USB_PORT_FEAT_C_ENABLE: 319 case USB_PORT_FEAT_C_OVER_CURRENT: 320 case USB_PORT_FEAT_C_RESET: 321 case USB_PORT_FEAT_C_SUSPEND: 322 break; 323 default: 324 goto error; 325 } 326 dev_dbg(musb->controller, "clear feature %d\n", wValue); 327 musb->port1_status &= ~(1 << wValue); 328 break; 329 case GetHubDescriptor: 330 { 331 struct usb_hub_descriptor *desc = (void *)buf; 332 333 desc->bDescLength = 9; 334 desc->bDescriptorType = 0x29; 335 desc->bNbrPorts = 1; 336 desc->wHubCharacteristics = cpu_to_le16( 337 0x0001 /* per-port power switching */ 338 | 0x0010 /* no overcurrent reporting */ 339 ); 340 desc->bPwrOn2PwrGood = 5; /* msec/2 */ 341 desc->bHubContrCurrent = 0; 342 343 /* workaround bogus struct definition */ 344 desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */ 345 desc->u.hs.DeviceRemovable[1] = 0xff; 346 } 347 break; 348 case GetHubStatus: 349 temp = 0; 350 *(__le32 *) buf = cpu_to_le32(temp); 351 break; 352 case GetPortStatus: 353 if (wIndex != 1) 354 goto error; 355 356 /* finish RESET signaling? */ 357 if ((musb->port1_status & USB_PORT_STAT_RESET) 358 && time_after_eq(jiffies, musb->rh_timer)) 359 musb_port_reset(musb, false); 360 361 /* finish RESUME signaling? */ 362 if ((musb->port1_status & MUSB_PORT_STAT_RESUME) 363 && time_after_eq(jiffies, musb->rh_timer)) { 364 u8 power; 365 366 power = musb_readb(musb->mregs, MUSB_POWER); 367 power &= ~MUSB_POWER_RESUME; 368 dev_dbg(musb->controller, "root port resume stopped, power %02x\n", 369 power); 370 musb_writeb(musb->mregs, MUSB_POWER, power); 371 372 /* ISSUE: DaVinci (RTL 1.300) disconnects after 373 * resume of high speed peripherals (but not full 374 * speed ones). 375 */ 376 377 musb->is_active = 1; 378 musb->port1_status &= ~(USB_PORT_STAT_SUSPEND 379 | MUSB_PORT_STAT_RESUME); 380 musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; 381 usb_hcd_poll_rh_status(musb_to_hcd(musb)); 382 /* NOTE: it might really be A_WAIT_BCON ... */ 383 musb->xceiv->state = OTG_STATE_A_HOST; 384 } 385 386 put_unaligned(cpu_to_le32(musb->port1_status 387 & ~MUSB_PORT_STAT_RESUME), 388 (__le32 *) buf); 389 390 /* port change status is more interesting */ 391 dev_dbg(musb->controller, "port status %08x\n", 392 musb->port1_status); 393 break; 394 case SetPortFeature: 395 if ((wIndex & 0xff) != 1) 396 goto error; 397 398 switch (wValue) { 399 case USB_PORT_FEAT_POWER: 400 /* NOTE: this controller has a strange state machine 401 * that involves "requesting sessions" according to 402 * magic side effects from incompletely-described 403 * rules about startup... 404 * 405 * This call is what really starts the host mode; be 406 * very careful about side effects if you reorder any 407 * initialization logic, e.g. for OTG, or change any 408 * logic relating to VBUS power-up. 409 */ 410 if (!hcd->self.is_b_host) 411 musb_start(musb); 412 break; 413 case USB_PORT_FEAT_RESET: 414 musb_port_reset(musb, true); 415 break; 416 case USB_PORT_FEAT_SUSPEND: 417 musb_port_suspend(musb, true); 418 break; 419 case USB_PORT_FEAT_TEST: 420 if (unlikely(is_host_active(musb))) 421 goto error; 422 423 wIndex >>= 8; 424 switch (wIndex) { 425 case 1: 426 pr_debug("TEST_J\n"); 427 temp = MUSB_TEST_J; 428 break; 429 case 2: 430 pr_debug("TEST_K\n"); 431 temp = MUSB_TEST_K; 432 break; 433 case 3: 434 pr_debug("TEST_SE0_NAK\n"); 435 temp = MUSB_TEST_SE0_NAK; 436 break; 437 case 4: 438 pr_debug("TEST_PACKET\n"); 439 temp = MUSB_TEST_PACKET; 440 musb_load_testpacket(musb); 441 break; 442 case 5: 443 pr_debug("TEST_FORCE_ENABLE\n"); 444 temp = MUSB_TEST_FORCE_HOST 445 | MUSB_TEST_FORCE_HS; 446 447 musb_writeb(musb->mregs, MUSB_DEVCTL, 448 MUSB_DEVCTL_SESSION); 449 break; 450 case 6: 451 pr_debug("TEST_FIFO_ACCESS\n"); 452 temp = MUSB_TEST_FIFO_ACCESS; 453 break; 454 default: 455 goto error; 456 } 457 musb_writeb(musb->mregs, MUSB_TESTMODE, temp); 458 break; 459 default: 460 goto error; 461 } 462 dev_dbg(musb->controller, "set feature %d\n", wValue); 463 musb->port1_status |= 1 << wValue; 464 break; 465 466 default: 467error: 468 /* "protocol stall" on error */ 469 retval = -EPIPE; 470 } 471 spin_unlock_irqrestore(&musb->lock, flags); 472 return retval; 473} 474