musb_virthub.c revision 6d349671174c5da77835dd1b82e874508167f57b
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 48static void musb_port_suspend(struct musb *musb, bool do_suspend) 49{ 50 struct usb_otg *otg = musb->xceiv->otg; 51 u8 power; 52 void __iomem *mbase = musb->mregs; 53 54 if (!is_host_active(musb)) 55 return; 56 57 /* NOTE: this doesn't necessarily put PHY into low power mode, 58 * turning off its clock; that's a function of PHY integration and 59 * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect 60 * SE0 changing to connect (J) or wakeup (K) states. 61 */ 62 power = musb_readb(mbase, MUSB_POWER); 63 if (do_suspend) { 64 int retries = 10000; 65 66 power &= ~MUSB_POWER_RESUME; 67 power |= MUSB_POWER_SUSPENDM; 68 musb_writeb(mbase, MUSB_POWER, power); 69 70 /* Needed for OPT A tests */ 71 power = musb_readb(mbase, MUSB_POWER); 72 while (power & MUSB_POWER_SUSPENDM) { 73 power = musb_readb(mbase, MUSB_POWER); 74 if (retries-- < 1) 75 break; 76 } 77 78 dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); 79 80 musb->port1_status |= USB_PORT_STAT_SUSPEND; 81 switch (musb->xceiv->state) { 82 case OTG_STATE_A_HOST: 83 musb->xceiv->state = OTG_STATE_A_SUSPEND; 84 musb->is_active = otg->host->b_hnp_enable; 85 if (musb->is_active) 86 mod_timer(&musb->otg_timer, jiffies 87 + msecs_to_jiffies( 88 OTG_TIME_A_AIDL_BDIS)); 89 musb_platform_try_idle(musb, 0); 90 break; 91 case OTG_STATE_B_HOST: 92 musb->xceiv->state = OTG_STATE_B_WAIT_ACON; 93 musb->is_active = otg->host->b_hnp_enable; 94 musb_platform_try_idle(musb, 0); 95 break; 96 default: 97 dev_dbg(musb->controller, "bogus rh suspend? %s\n", 98 usb_otg_state_string(musb->xceiv->state)); 99 } 100 } else if (power & MUSB_POWER_SUSPENDM) { 101 power &= ~MUSB_POWER_SUSPENDM; 102 power |= MUSB_POWER_RESUME; 103 musb_writeb(mbase, MUSB_POWER, power); 104 105 dev_dbg(musb->controller, "Root port resuming, power %02x\n", power); 106 107 /* later, GetPortStatus will stop RESUME signaling */ 108 musb->port1_status |= MUSB_PORT_STAT_RESUME; 109 musb->rh_timer = jiffies + msecs_to_jiffies(20); 110 } 111} 112 113static void musb_port_reset(struct musb *musb, bool do_reset) 114{ 115 u8 power; 116 void __iomem *mbase = musb->mregs; 117 118 if (musb->xceiv->state == OTG_STATE_B_IDLE) { 119 dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); 120 musb->port1_status &= ~USB_PORT_STAT_RESET; 121 return; 122 } 123 124 if (!is_host_active(musb)) 125 return; 126 127 /* NOTE: caller guarantees it will turn off the reset when 128 * the appropriate amount of time has passed 129 */ 130 power = musb_readb(mbase, MUSB_POWER); 131 if (do_reset) { 132 133 /* 134 * If RESUME is set, we must make sure it stays minimum 20 ms. 135 * Then we must clear RESUME and wait a bit to let musb start 136 * generating SOFs. If we don't do this, OPT HS A 6.8 tests 137 * fail with "Error! Did not receive an SOF before suspend 138 * detected". 139 */ 140 if (power & MUSB_POWER_RESUME) { 141 while (time_before(jiffies, musb->rh_timer)) 142 msleep(1); 143 musb_writeb(mbase, MUSB_POWER, 144 power & ~MUSB_POWER_RESUME); 145 msleep(1); 146 } 147 148 power &= 0xf0; 149 musb_writeb(mbase, MUSB_POWER, 150 power | MUSB_POWER_RESET); 151 152 musb->port1_status |= USB_PORT_STAT_RESET; 153 musb->port1_status &= ~USB_PORT_STAT_ENABLE; 154 musb->rh_timer = jiffies + msecs_to_jiffies(50); 155 } else { 156 dev_dbg(musb->controller, "root port reset stopped\n"); 157 musb_writeb(mbase, MUSB_POWER, 158 power & ~MUSB_POWER_RESET); 159 160 power = musb_readb(mbase, MUSB_POWER); 161 if (power & MUSB_POWER_HSMODE) { 162 dev_dbg(musb->controller, "high-speed device connected\n"); 163 musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; 164 } 165 166 musb->port1_status &= ~USB_PORT_STAT_RESET; 167 musb->port1_status |= USB_PORT_STAT_ENABLE 168 | (USB_PORT_STAT_C_RESET << 16) 169 | (USB_PORT_STAT_C_ENABLE << 16); 170 usb_hcd_poll_rh_status(musb_to_hcd(musb)); 171 172 musb->vbuserr_retry = VBUSERR_RETRY_COUNT; 173 } 174} 175 176void musb_root_disconnect(struct musb *musb) 177{ 178 struct usb_otg *otg = musb->xceiv->otg; 179 180 musb->port1_status = USB_PORT_STAT_POWER 181 | (USB_PORT_STAT_C_CONNECTION << 16); 182 183 usb_hcd_poll_rh_status(musb_to_hcd(musb)); 184 musb->is_active = 0; 185 186 switch (musb->xceiv->state) { 187 case OTG_STATE_A_SUSPEND: 188 if (otg->host->b_hnp_enable) { 189 musb->xceiv->state = OTG_STATE_A_PERIPHERAL; 190 musb->g.is_a_peripheral = 1; 191 break; 192 } 193 /* FALLTHROUGH */ 194 case OTG_STATE_A_HOST: 195 musb->xceiv->state = OTG_STATE_A_WAIT_BCON; 196 musb->is_active = 0; 197 break; 198 case OTG_STATE_A_WAIT_VFALL: 199 musb->xceiv->state = OTG_STATE_B_IDLE; 200 break; 201 default: 202 dev_dbg(musb->controller, "host disconnect (%s)\n", 203 usb_otg_state_string(musb->xceiv->state)); 204 } 205} 206 207 208/*---------------------------------------------------------------------*/ 209 210/* Caller may or may not hold musb->lock */ 211int musb_hub_status_data(struct usb_hcd *hcd, char *buf) 212{ 213 struct musb *musb = hcd_to_musb(hcd); 214 int retval = 0; 215 216 /* called in_irq() via usb_hcd_poll_rh_status() */ 217 if (musb->port1_status & 0xffff0000) { 218 *buf = 0x02; 219 retval = 1; 220 } 221 return retval; 222} 223 224int musb_hub_control( 225 struct usb_hcd *hcd, 226 u16 typeReq, 227 u16 wValue, 228 u16 wIndex, 229 char *buf, 230 u16 wLength) 231{ 232 struct musb *musb = hcd_to_musb(hcd); 233 u32 temp; 234 int retval = 0; 235 unsigned long flags; 236 237 spin_lock_irqsave(&musb->lock, flags); 238 239 if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) { 240 spin_unlock_irqrestore(&musb->lock, flags); 241 return -ESHUTDOWN; 242 } 243 244 /* hub features: always zero, setting is a NOP 245 * port features: reported, sometimes updated when host is active 246 * no indicators 247 */ 248 switch (typeReq) { 249 case ClearHubFeature: 250 case SetHubFeature: 251 switch (wValue) { 252 case C_HUB_OVER_CURRENT: 253 case C_HUB_LOCAL_POWER: 254 break; 255 default: 256 goto error; 257 } 258 break; 259 case ClearPortFeature: 260 if ((wIndex & 0xff) != 1) 261 goto error; 262 263 switch (wValue) { 264 case USB_PORT_FEAT_ENABLE: 265 break; 266 case USB_PORT_FEAT_SUSPEND: 267 musb_port_suspend(musb, false); 268 break; 269 case USB_PORT_FEAT_POWER: 270 if (!hcd->self.is_b_host) 271 musb_platform_set_vbus(musb, 0); 272 break; 273 case USB_PORT_FEAT_C_CONNECTION: 274 case USB_PORT_FEAT_C_ENABLE: 275 case USB_PORT_FEAT_C_OVER_CURRENT: 276 case USB_PORT_FEAT_C_RESET: 277 case USB_PORT_FEAT_C_SUSPEND: 278 break; 279 default: 280 goto error; 281 } 282 dev_dbg(musb->controller, "clear feature %d\n", wValue); 283 musb->port1_status &= ~(1 << wValue); 284 break; 285 case GetHubDescriptor: 286 { 287 struct usb_hub_descriptor *desc = (void *)buf; 288 289 desc->bDescLength = 9; 290 desc->bDescriptorType = 0x29; 291 desc->bNbrPorts = 1; 292 desc->wHubCharacteristics = cpu_to_le16( 293 0x0001 /* per-port power switching */ 294 | 0x0010 /* no overcurrent reporting */ 295 ); 296 desc->bPwrOn2PwrGood = 5; /* msec/2 */ 297 desc->bHubContrCurrent = 0; 298 299 /* workaround bogus struct definition */ 300 desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */ 301 desc->u.hs.DeviceRemovable[1] = 0xff; 302 } 303 break; 304 case GetHubStatus: 305 temp = 0; 306 *(__le32 *) buf = cpu_to_le32(temp); 307 break; 308 case GetPortStatus: 309 if (wIndex != 1) 310 goto error; 311 312 /* finish RESET signaling? */ 313 if ((musb->port1_status & USB_PORT_STAT_RESET) 314 && time_after_eq(jiffies, musb->rh_timer)) 315 musb_port_reset(musb, false); 316 317 /* finish RESUME signaling? */ 318 if ((musb->port1_status & MUSB_PORT_STAT_RESUME) 319 && time_after_eq(jiffies, musb->rh_timer)) { 320 u8 power; 321 322 power = musb_readb(musb->mregs, MUSB_POWER); 323 power &= ~MUSB_POWER_RESUME; 324 dev_dbg(musb->controller, "root port resume stopped, power %02x\n", 325 power); 326 musb_writeb(musb->mregs, MUSB_POWER, power); 327 328 /* ISSUE: DaVinci (RTL 1.300) disconnects after 329 * resume of high speed peripherals (but not full 330 * speed ones). 331 */ 332 333 musb->is_active = 1; 334 musb->port1_status &= ~(USB_PORT_STAT_SUSPEND 335 | MUSB_PORT_STAT_RESUME); 336 musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; 337 usb_hcd_poll_rh_status(musb_to_hcd(musb)); 338 /* NOTE: it might really be A_WAIT_BCON ... */ 339 musb->xceiv->state = OTG_STATE_A_HOST; 340 } 341 342 put_unaligned(cpu_to_le32(musb->port1_status 343 & ~MUSB_PORT_STAT_RESUME), 344 (__le32 *) buf); 345 346 /* port change status is more interesting */ 347 dev_dbg(musb->controller, "port status %08x\n", 348 musb->port1_status); 349 break; 350 case SetPortFeature: 351 if ((wIndex & 0xff) != 1) 352 goto error; 353 354 switch (wValue) { 355 case USB_PORT_FEAT_POWER: 356 /* NOTE: this controller has a strange state machine 357 * that involves "requesting sessions" according to 358 * magic side effects from incompletely-described 359 * rules about startup... 360 * 361 * This call is what really starts the host mode; be 362 * very careful about side effects if you reorder any 363 * initialization logic, e.g. for OTG, or change any 364 * logic relating to VBUS power-up. 365 */ 366 if (!hcd->self.is_b_host) 367 musb_start(musb); 368 break; 369 case USB_PORT_FEAT_RESET: 370 musb_port_reset(musb, true); 371 break; 372 case USB_PORT_FEAT_SUSPEND: 373 musb_port_suspend(musb, true); 374 break; 375 case USB_PORT_FEAT_TEST: 376 if (unlikely(is_host_active(musb))) 377 goto error; 378 379 wIndex >>= 8; 380 switch (wIndex) { 381 case 1: 382 pr_debug("TEST_J\n"); 383 temp = MUSB_TEST_J; 384 break; 385 case 2: 386 pr_debug("TEST_K\n"); 387 temp = MUSB_TEST_K; 388 break; 389 case 3: 390 pr_debug("TEST_SE0_NAK\n"); 391 temp = MUSB_TEST_SE0_NAK; 392 break; 393 case 4: 394 pr_debug("TEST_PACKET\n"); 395 temp = MUSB_TEST_PACKET; 396 musb_load_testpacket(musb); 397 break; 398 case 5: 399 pr_debug("TEST_FORCE_ENABLE\n"); 400 temp = MUSB_TEST_FORCE_HOST 401 | MUSB_TEST_FORCE_HS; 402 403 musb_writeb(musb->mregs, MUSB_DEVCTL, 404 MUSB_DEVCTL_SESSION); 405 break; 406 case 6: 407 pr_debug("TEST_FIFO_ACCESS\n"); 408 temp = MUSB_TEST_FIFO_ACCESS; 409 break; 410 default: 411 goto error; 412 } 413 musb_writeb(musb->mregs, MUSB_TESTMODE, temp); 414 break; 415 default: 416 goto error; 417 } 418 dev_dbg(musb->controller, "set feature %d\n", wValue); 419 musb->port1_status |= 1 << wValue; 420 break; 421 422 default: 423error: 424 /* "protocol stall" on error */ 425 retval = -EPIPE; 426 } 427 spin_unlock_irqrestore(&musb->lock, flags); 428 return retval; 429} 430