diff options
Diffstat (limited to 'drivers/usb/host/ehci-tegra.c')
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index a516af28c29b..02b2bfd49a10 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c | |||
@@ -58,6 +58,71 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) | |||
58 | clk_disable(tegra->emc_clk); | 58 | clk_disable(tegra->emc_clk); |
59 | } | 59 | } |
60 | 60 | ||
61 | static int tegra_ehci_internal_port_reset( | ||
62 | struct ehci_hcd *ehci, | ||
63 | u32 __iomem *portsc_reg | ||
64 | ) | ||
65 | { | ||
66 | u32 temp; | ||
67 | unsigned long flags; | ||
68 | int retval = 0; | ||
69 | int i, tries; | ||
70 | u32 saved_usbintr; | ||
71 | |||
72 | spin_lock_irqsave(&ehci->lock, flags); | ||
73 | saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable); | ||
74 | /* disable USB interrupt */ | ||
75 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); | ||
76 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
77 | |||
78 | /* | ||
79 | * Here we have to do Port Reset at most twice for | ||
80 | * Port Enable bit to be set. | ||
81 | */ | ||
82 | for (i = 0; i < 2; i++) { | ||
83 | temp = ehci_readl(ehci, portsc_reg); | ||
84 | temp |= PORT_RESET; | ||
85 | ehci_writel(ehci, temp, portsc_reg); | ||
86 | mdelay(10); | ||
87 | temp &= ~PORT_RESET; | ||
88 | ehci_writel(ehci, temp, portsc_reg); | ||
89 | mdelay(1); | ||
90 | tries = 100; | ||
91 | do { | ||
92 | mdelay(1); | ||
93 | /* | ||
94 | * Up to this point, Port Enable bit is | ||
95 | * expected to be set after 2 ms waiting. | ||
96 | * USB1 usually takes extra 45 ms, for safety, | ||
97 | * we take 100 ms as timeout. | ||
98 | */ | ||
99 | temp = ehci_readl(ehci, portsc_reg); | ||
100 | } while (!(temp & PORT_PE) && tries--); | ||
101 | if (temp & PORT_PE) | ||
102 | break; | ||
103 | } | ||
104 | if (i == 2) | ||
105 | retval = -ETIMEDOUT; | ||
106 | |||
107 | /* | ||
108 | * Clear Connect Status Change bit if it's set. | ||
109 | * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared. | ||
110 | */ | ||
111 | if (temp & PORT_CSC) | ||
112 | ehci_writel(ehci, PORT_CSC, portsc_reg); | ||
113 | |||
114 | /* | ||
115 | * Write to clear any interrupt status bits that might be set | ||
116 | * during port reset. | ||
117 | */ | ||
118 | temp = ehci_readl(ehci, &ehci->regs->status); | ||
119 | ehci_writel(ehci, temp, &ehci->regs->status); | ||
120 | |||
121 | /* restore original interrupt enable bits */ | ||
122 | ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable); | ||
123 | return retval; | ||
124 | } | ||
125 | |||
61 | static int tegra_ehci_hub_control( | 126 | static int tegra_ehci_hub_control( |
62 | struct usb_hcd *hcd, | 127 | struct usb_hcd *hcd, |
63 | u16 typeReq, | 128 | u16 typeReq, |
@@ -121,6 +186,13 @@ static int tegra_ehci_hub_control( | |||
121 | goto done; | 186 | goto done; |
122 | } | 187 | } |
123 | 188 | ||
189 | /* For USB1 port we need to issue Port Reset twice internally */ | ||
190 | if (tegra->phy->instance == 0 && | ||
191 | (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { | ||
192 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
193 | return tegra_ehci_internal_port_reset(ehci, status_reg); | ||
194 | } | ||
195 | |||
124 | /* | 196 | /* |
125 | * Tegra host controller will time the resume operation to clear the bit | 197 | * Tegra host controller will time the resume operation to clear the bit |
126 | * when the port control state switches to HS or FS Idle. This behavior | 198 | * when the port control state switches to HS or FS Idle. This behavior |
@@ -328,7 +400,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) | |||
328 | /* EHCI registers start at offset 0x100 */ | 400 | /* EHCI registers start at offset 0x100 */ |
329 | ehci->caps = hcd->regs + 0x100; | 401 | ehci->caps = hcd->regs + 0x100; |
330 | ehci->regs = hcd->regs + 0x100 + | 402 | ehci->regs = hcd->regs + 0x100 + |
331 | HC_LENGTH(readl(&ehci->caps->hc_capbase)); | 403 | HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); |
332 | 404 | ||
333 | dbg_hcs_params(ehci, "reset"); | 405 | dbg_hcs_params(ehci, "reset"); |
334 | dbg_hcc_params(ehci, "reset"); | 406 | dbg_hcc_params(ehci, "reset"); |