diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2011-09-13 11:54:39 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-04-30 04:31:21 -0400 |
commit | e6a3b5e2888b51e37c65c97dae966f793bc4806a (patch) | |
tree | 934c2a7578d15dedbe2221c28cbdff7afd28588f | |
parent | 51249dca627d9d0e6b41531e716cbc308554a62c (diff) |
usb: dwc3: ep0: add LPM handling
On device loading the driver enables LPM and the acceptance of U1 and U2
states. The [Set|Clear]Feature requests for "U1/U2" are forwarded
directly to the hardware and allow / forbid the initiation of the low
power links.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/dwc3/core.h | 1 | ||||
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 46 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 9 |
3 files changed, 45 insertions, 11 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c7b3ca037bbc..93f9973ad53e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h | |||
@@ -194,6 +194,7 @@ | |||
194 | #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 | 194 | #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 |
195 | 195 | ||
196 | /* Device Configuration Register */ | 196 | /* Device Configuration Register */ |
197 | #define DWC3_DCFG_LPM_CAP (1 << 22) | ||
197 | #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) | 198 | #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) |
198 | #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) | 199 | #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) |
199 | 200 | ||
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 25910e251c04..18494b0d7d6e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c | |||
@@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, | |||
261 | { | 261 | { |
262 | struct dwc3_ep *dep; | 262 | struct dwc3_ep *dep; |
263 | u32 recip; | 263 | u32 recip; |
264 | u32 reg; | ||
264 | u16 usb_status = 0; | 265 | u16 usb_status = 0; |
265 | __le16 *response_pkt; | 266 | __le16 *response_pkt; |
266 | 267 | ||
@@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, | |||
268 | switch (recip) { | 269 | switch (recip) { |
269 | case USB_RECIP_DEVICE: | 270 | case USB_RECIP_DEVICE: |
270 | /* | 271 | /* |
271 | * We are self-powered. U1/U2/LTM will be set later | 272 | * LTM will be set once we know how to set this in HW. |
272 | * once we handle this states. RemoteWakeup is 0 on SS | ||
273 | */ | 273 | */ |
274 | usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; | 274 | usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; |
275 | |||
276 | if (dwc->speed == DWC3_DSTS_SUPERSPEED) { | ||
277 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | ||
278 | if (reg & DWC3_DCTL_INITU1ENA) | ||
279 | usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; | ||
280 | if (reg & DWC3_DCTL_INITU2ENA) | ||
281 | usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; | ||
282 | } | ||
283 | |||
275 | break; | 284 | break; |
276 | 285 | ||
277 | case USB_RECIP_INTERFACE: | 286 | case USB_RECIP_INTERFACE: |
@@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, | |||
312 | u32 recip; | 321 | u32 recip; |
313 | u32 wValue; | 322 | u32 wValue; |
314 | u32 wIndex; | 323 | u32 wIndex; |
324 | u32 reg; | ||
315 | int ret; | 325 | int ret; |
316 | 326 | ||
317 | wValue = le16_to_cpu(ctrl->wValue); | 327 | wValue = le16_to_cpu(ctrl->wValue); |
@@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, | |||
320 | switch (recip) { | 330 | switch (recip) { |
321 | case USB_RECIP_DEVICE: | 331 | case USB_RECIP_DEVICE: |
322 | 332 | ||
333 | switch (wValue) { | ||
334 | case USB_DEVICE_REMOTE_WAKEUP: | ||
335 | break; | ||
323 | /* | 336 | /* |
324 | * 9.4.1 says only only for SS, in AddressState only for | 337 | * 9.4.1 says only only for SS, in AddressState only for |
325 | * default control pipe | 338 | * default control pipe |
326 | */ | 339 | */ |
327 | switch (wValue) { | ||
328 | case USB_DEVICE_U1_ENABLE: | 340 | case USB_DEVICE_U1_ENABLE: |
329 | case USB_DEVICE_U2_ENABLE: | ||
330 | case USB_DEVICE_LTM_ENABLE: | ||
331 | if (dwc->dev_state != DWC3_CONFIGURED_STATE) | 341 | if (dwc->dev_state != DWC3_CONFIGURED_STATE) |
332 | return -EINVAL; | 342 | return -EINVAL; |
333 | if (dwc->speed != DWC3_DSTS_SUPERSPEED) | 343 | if (dwc->speed != DWC3_DSTS_SUPERSPEED) |
334 | return -EINVAL; | 344 | return -EINVAL; |
335 | } | ||
336 | 345 | ||
337 | /* XXX add U[12] & LTM */ | 346 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); |
338 | switch (wValue) { | 347 | if (set) |
339 | case USB_DEVICE_REMOTE_WAKEUP: | 348 | reg |= DWC3_DCTL_INITU1ENA; |
340 | break; | 349 | else |
341 | case USB_DEVICE_U1_ENABLE: | 350 | reg &= ~DWC3_DCTL_INITU1ENA; |
351 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | ||
342 | break; | 352 | break; |
353 | |||
343 | case USB_DEVICE_U2_ENABLE: | 354 | case USB_DEVICE_U2_ENABLE: |
355 | if (dwc->dev_state != DWC3_CONFIGURED_STATE) | ||
356 | return -EINVAL; | ||
357 | if (dwc->speed != DWC3_DSTS_SUPERSPEED) | ||
358 | return -EINVAL; | ||
359 | |||
360 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | ||
361 | if (set) | ||
362 | reg |= DWC3_DCTL_INITU2ENA; | ||
363 | else | ||
364 | reg &= ~DWC3_DCTL_INITU2ENA; | ||
365 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | ||
344 | break; | 366 | break; |
367 | |||
345 | case USB_DEVICE_LTM_ENABLE: | 368 | case USB_DEVICE_LTM_ENABLE: |
369 | return -EINVAL; | ||
346 | break; | 370 | break; |
347 | 371 | ||
348 | case USB_DEVICE_TEST_MODE: | 372 | case USB_DEVICE_TEST_MODE: |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dda56b8f8617..906db570ef4f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -1933,6 +1933,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) | |||
1933 | 1933 | ||
1934 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | 1934 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); |
1935 | reg &= ~DWC3_DCTL_TSTCTRL_MASK; | 1935 | reg &= ~DWC3_DCTL_TSTCTRL_MASK; |
1936 | reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA); | ||
1936 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | 1937 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); |
1937 | dwc->test_mode = false; | 1938 | dwc->test_mode = false; |
1938 | 1939 | ||
@@ -2330,6 +2331,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) | |||
2330 | goto err5; | 2331 | goto err5; |
2331 | } | 2332 | } |
2332 | 2333 | ||
2334 | reg = dwc3_readl(dwc->regs, DWC3_DCFG); | ||
2335 | reg |= DWC3_DCFG_LPM_CAP; | ||
2336 | dwc3_writel(dwc->regs, DWC3_DCFG, reg); | ||
2337 | |||
2338 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | ||
2339 | reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA; | ||
2340 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | ||
2341 | |||
2333 | /* Enable all but Start and End of Frame IRQs */ | 2342 | /* Enable all but Start and End of Frame IRQs */ |
2334 | reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | | 2343 | reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | |
2335 | DWC3_DEVTEN_EVNTOVERFLOWEN | | 2344 | DWC3_DEVTEN_EVNTOVERFLOWEN | |