Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
musb_virthub.c
Go to the documentation of this file.
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 static 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 
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
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  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 */
109  musb->rh_timer = jiffies + msecs_to_jiffies(20);
110  }
111 }
112 
113 static 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");
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  musb->ignore_disconnect = true;
149  power &= 0xf0;
150  musb_writeb(mbase, MUSB_POWER,
151  power | MUSB_POWER_RESET);
152 
155  musb->rh_timer = jiffies + msecs_to_jiffies(50);
156  } else {
157  dev_dbg(musb->controller, "root port reset stopped\n");
158  musb_writeb(mbase, MUSB_POWER,
159  power & ~MUSB_POWER_RESET);
160 
161  musb->ignore_disconnect = false;
162 
163  power = musb_readb(mbase, MUSB_POWER);
164  if (power & MUSB_POWER_HSMODE) {
165  dev_dbg(musb->controller, "high-speed device connected\n");
167  }
168 
171  | (USB_PORT_STAT_C_RESET << 16)
172  | (USB_PORT_STAT_C_ENABLE << 16);
173  usb_hcd_poll_rh_status(musb_to_hcd(musb));
174 
176  }
177 }
178 
179 void musb_root_disconnect(struct musb *musb)
180 {
181  struct usb_otg *otg = musb->xceiv->otg;
182 
184  | (USB_PORT_STAT_C_CONNECTION << 16);
185 
186  usb_hcd_poll_rh_status(musb_to_hcd(musb));
187  musb->is_active = 0;
188 
189  switch (musb->xceiv->state) {
190  case OTG_STATE_A_SUSPEND:
191  if (otg->host->b_hnp_enable) {
192  musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
193  musb->g.is_a_peripheral = 1;
194  break;
195  }
196  /* FALLTHROUGH */
197  case OTG_STATE_A_HOST:
198  musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
199  musb->is_active = 0;
200  break;
202  musb->xceiv->state = OTG_STATE_B_IDLE;
203  break;
204  default:
205  dev_dbg(musb->controller, "host disconnect (%s)\n",
206  otg_state_string(musb->xceiv->state));
207  }
208 }
209 
210 
211 /*---------------------------------------------------------------------*/
212 
213 /* Caller may or may not hold musb->lock */
214 int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
215 {
216  struct musb *musb = hcd_to_musb(hcd);
217  int retval = 0;
218 
219  /* called in_irq() via usb_hcd_poll_rh_status() */
220  if (musb->port1_status & 0xffff0000) {
221  *buf = 0x02;
222  retval = 1;
223  }
224  return retval;
225 }
226 
228  struct usb_hcd *hcd,
229  u16 typeReq,
230  u16 wValue,
231  u16 wIndex,
232  char *buf,
233  u16 wLength)
234 {
235  struct musb *musb = hcd_to_musb(hcd);
236  u32 temp;
237  int retval = 0;
238  unsigned long flags;
239 
240  spin_lock_irqsave(&musb->lock, flags);
241 
242  if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) {
243  spin_unlock_irqrestore(&musb->lock, flags);
244  return -ESHUTDOWN;
245  }
246 
247  /* hub features: always zero, setting is a NOP
248  * port features: reported, sometimes updated when host is active
249  * no indicators
250  */
251  switch (typeReq) {
252  case ClearHubFeature:
253  case SetHubFeature:
254  switch (wValue) {
255  case C_HUB_OVER_CURRENT:
256  case C_HUB_LOCAL_POWER:
257  break;
258  default:
259  goto error;
260  }
261  break;
262  case ClearPortFeature:
263  if ((wIndex & 0xff) != 1)
264  goto error;
265 
266  switch (wValue) {
268  break;
270  musb_port_suspend(musb, false);
271  break;
272  case USB_PORT_FEAT_POWER:
273  if (!hcd->self.is_b_host)
274  musb_platform_set_vbus(musb, 0);
275  break;
281  break;
282  default:
283  goto error;
284  }
285  dev_dbg(musb->controller, "clear feature %d\n", wValue);
286  musb->port1_status &= ~(1 << wValue);
287  break;
288  case GetHubDescriptor:
289  {
290  struct usb_hub_descriptor *desc = (void *)buf;
291 
292  desc->bDescLength = 9;
293  desc->bDescriptorType = 0x29;
294  desc->bNbrPorts = 1;
296  0x0001 /* per-port power switching */
297  | 0x0010 /* no overcurrent reporting */
298  );
299  desc->bPwrOn2PwrGood = 5; /* msec/2 */
300  desc->bHubContrCurrent = 0;
301 
302  /* workaround bogus struct definition */
303  desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */
304  desc->u.hs.DeviceRemovable[1] = 0xff;
305  }
306  break;
307  case GetHubStatus:
308  temp = 0;
309  *(__le32 *) buf = cpu_to_le32(temp);
310  break;
311  case GetPortStatus:
312  if (wIndex != 1)
313  goto error;
314 
315  /* finish RESET signaling? */
316  if ((musb->port1_status & USB_PORT_STAT_RESET)
317  && time_after_eq(jiffies, musb->rh_timer))
318  musb_port_reset(musb, false);
319 
320  /* finish RESUME signaling? */
321  if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
322  && time_after_eq(jiffies, musb->rh_timer)) {
323  u8 power;
324 
325  power = musb_readb(musb->mregs, MUSB_POWER);
326  power &= ~MUSB_POWER_RESUME;
327  dev_dbg(musb->controller, "root port resume stopped, power %02x\n",
328  power);
329  musb_writeb(musb->mregs, MUSB_POWER, power);
330 
331  /* ISSUE: DaVinci (RTL 1.300) disconnects after
332  * resume of high speed peripherals (but not full
333  * speed ones).
334  */
335 
336  musb->is_active = 1;
339  musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
340  usb_hcd_poll_rh_status(musb_to_hcd(musb));
341  /* NOTE: it might really be A_WAIT_BCON ... */
342  musb->xceiv->state = OTG_STATE_A_HOST;
343  }
344 
347  (__le32 *) buf);
348 
349  /* port change status is more interesting */
350  dev_dbg(musb->controller, "port status %08x\n",
351  musb->port1_status);
352  break;
353  case SetPortFeature:
354  if ((wIndex & 0xff) != 1)
355  goto error;
356 
357  switch (wValue) {
358  case USB_PORT_FEAT_POWER:
359  /* NOTE: this controller has a strange state machine
360  * that involves "requesting sessions" according to
361  * magic side effects from incompletely-described
362  * rules about startup...
363  *
364  * This call is what really starts the host mode; be
365  * very careful about side effects if you reorder any
366  * initialization logic, e.g. for OTG, or change any
367  * logic relating to VBUS power-up.
368  */
369  if (!hcd->self.is_b_host)
370  musb_start(musb);
371  break;
372  case USB_PORT_FEAT_RESET:
373  musb_port_reset(musb, true);
374  break;
376  musb_port_suspend(musb, true);
377  break;
378  case USB_PORT_FEAT_TEST:
379  if (unlikely(is_host_active(musb)))
380  goto error;
381 
382  wIndex >>= 8;
383  switch (wIndex) {
384  case 1:
385  pr_debug("TEST_J\n");
386  temp = MUSB_TEST_J;
387  break;
388  case 2:
389  pr_debug("TEST_K\n");
390  temp = MUSB_TEST_K;
391  break;
392  case 3:
393  pr_debug("TEST_SE0_NAK\n");
394  temp = MUSB_TEST_SE0_NAK;
395  break;
396  case 4:
397  pr_debug("TEST_PACKET\n");
398  temp = MUSB_TEST_PACKET;
399  musb_load_testpacket(musb);
400  break;
401  case 5:
402  pr_debug("TEST_FORCE_ENABLE\n");
403  temp = MUSB_TEST_FORCE_HOST
405 
406  musb_writeb(musb->mregs, MUSB_DEVCTL,
408  break;
409  case 6:
410  pr_debug("TEST_FIFO_ACCESS\n");
411  temp = MUSB_TEST_FIFO_ACCESS;
412  break;
413  default:
414  goto error;
415  }
416  musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
417  break;
418  default:
419  goto error;
420  }
421  dev_dbg(musb->controller, "set feature %d\n", wValue);
422  musb->port1_status |= 1 << wValue;
423  break;
424 
425  default:
426 error:
427  /* "protocol stall" on error */
428  retval = -EPIPE;
429  }
430  spin_unlock_irqrestore(&musb->lock, flags);
431  return retval;
432 }