diff options
author | Paul Zimmerman <Paul.Zimmerman@synopsys.com> | 2012-04-27 06:10:52 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-06-03 16:08:23 -0400 |
commit | 802fde983e8a3391e059bd41fc272993ae642816 (patch) | |
tree | 8f54686b7195e1762154ab1de4c515182ada62d8 /drivers/usb/dwc3/gadget.c | |
parent | d7a46a8dfc45191b39daa19c05d3ff74d1881f15 (diff) |
usb: dwc3: support new revisions of DWC3 core
Recent cores (>= 1.94a) have a set of new features,
commands and a slightly different programming model.
This patch aims to support those changes.
Signed-off-by: Paul Zimmerman <paulz@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 852bde5cc139..04048333ec1a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) | |||
100 | int retries = 10000; | 100 | int retries = 10000; |
101 | u32 reg; | 101 | u32 reg; |
102 | 102 | ||
103 | /* | ||
104 | * Wait until device controller is ready. Only applies to 1.94a and | ||
105 | * later RTL. | ||
106 | */ | ||
107 | if (dwc->revision >= DWC3_REVISION_194A) { | ||
108 | while (--retries) { | ||
109 | reg = dwc3_readl(dwc->regs, DWC3_DSTS); | ||
110 | if (reg & DWC3_DSTS_DCNRD) | ||
111 | udelay(5); | ||
112 | else | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (retries <= 0) | ||
117 | return -ETIMEDOUT; | ||
118 | } | ||
119 | |||
103 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | 120 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); |
104 | reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; | 121 | reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; |
105 | 122 | ||
@@ -107,6 +124,13 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) | |||
107 | reg |= DWC3_DCTL_ULSTCHNGREQ(state); | 124 | reg |= DWC3_DCTL_ULSTCHNGREQ(state); |
108 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | 125 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); |
109 | 126 | ||
127 | /* | ||
128 | * The following code is racy when called from dwc3_gadget_wakeup, | ||
129 | * and is not needed, at least on newer versions | ||
130 | */ | ||
131 | if (dwc->revision >= DWC3_REVISION_194A) | ||
132 | return 0; | ||
133 | |||
110 | /* wait for a change in DSTS */ | 134 | /* wait for a change in DSTS */ |
111 | retries = 10000; | 135 | retries = 10000; |
112 | while (--retries) { | 136 | while (--retries) { |
@@ -266,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) | |||
266 | return "Clear Stall"; | 290 | return "Clear Stall"; |
267 | case DWC3_DEPCMD_SETSTALL: | 291 | case DWC3_DEPCMD_SETSTALL: |
268 | return "Set Stall"; | 292 | return "Set Stall"; |
269 | case DWC3_DEPCMD_GETSEQNUMBER: | 293 | case DWC3_DEPCMD_GETEPSTATE: |
270 | return "Get Data Sequence Number"; | 294 | return "Get Endpoint State"; |
271 | case DWC3_DEPCMD_SETTRANSFRESOURCE: | 295 | case DWC3_DEPCMD_SETTRANSFRESOURCE: |
272 | return "Set Endpoint Transfer Resource"; | 296 | return "Set Endpoint Transfer Resource"; |
273 | case DWC3_DEPCMD_SETEPCONFIG: | 297 | case DWC3_DEPCMD_SETEPCONFIG: |
@@ -1280,9 +1304,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) | |||
1280 | goto out; | 1304 | goto out; |
1281 | } | 1305 | } |
1282 | 1306 | ||
1283 | /* write zeroes to Link Change Request */ | 1307 | /* Recent versions do this automatically */ |
1284 | reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; | 1308 | if (dwc->revision < DWC3_REVISION_194A) { |
1285 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | 1309 | /* write zeroes to Link Change Request */ |
1310 | reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; | ||
1311 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | ||
1312 | } | ||
1286 | 1313 | ||
1287 | /* poll until Link State changes to ON */ | 1314 | /* poll until Link State changes to ON */ |
1288 | timeout = jiffies + msecs_to_jiffies(100); | 1315 | timeout = jiffies + msecs_to_jiffies(100); |
@@ -1326,9 +1353,14 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) | |||
1326 | 1353 | ||
1327 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | 1354 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); |
1328 | if (is_on) { | 1355 | if (is_on) { |
1329 | reg &= ~DWC3_DCTL_TRGTULST_MASK; | 1356 | if (dwc->revision <= DWC3_REVISION_187A) { |
1330 | reg |= (DWC3_DCTL_RUN_STOP | 1357 | reg &= ~DWC3_DCTL_TRGTULST_MASK; |
1331 | | DWC3_DCTL_TRGTULST_RX_DET); | 1358 | reg |= DWC3_DCTL_TRGTULST_RX_DET; |
1359 | } | ||
1360 | |||
1361 | if (dwc->revision >= DWC3_REVISION_194A) | ||
1362 | reg &= ~DWC3_DCTL_KEEP_CONNECT; | ||
1363 | reg |= DWC3_DCTL_RUN_STOP; | ||
1332 | } else { | 1364 | } else { |
1333 | reg &= ~DWC3_DCTL_RUN_STOP; | 1365 | reg &= ~DWC3_DCTL_RUN_STOP; |
1334 | } | 1366 | } |
@@ -1468,6 +1500,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g, | |||
1468 | 1500 | ||
1469 | return 0; | 1501 | return 0; |
1470 | } | 1502 | } |
1503 | |||
1471 | static const struct usb_gadget_ops dwc3_gadget_ops = { | 1504 | static const struct usb_gadget_ops dwc3_gadget_ops = { |
1472 | .get_frame = dwc3_gadget_get_frame, | 1505 | .get_frame = dwc3_gadget_get_frame, |
1473 | .wakeup = dwc3_gadget_wakeup, | 1506 | .wakeup = dwc3_gadget_wakeup, |
@@ -1962,9 +1995,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) | |||
1962 | /* after reset -> Default State */ | 1995 | /* after reset -> Default State */ |
1963 | dwc->dev_state = DWC3_DEFAULT_STATE; | 1996 | dwc->dev_state = DWC3_DEFAULT_STATE; |
1964 | 1997 | ||
1965 | /* Resume PHYs */ | 1998 | /* Recent versions support automatic phy suspend and don't need this */ |
1966 | dwc3_gadget_usb2_phy_suspend(dwc, false); | 1999 | if (dwc->revision < DWC3_REVISION_194A) { |
1967 | dwc3_gadget_usb3_phy_suspend(dwc, false); | 2000 | /* Resume PHYs */ |
2001 | dwc3_gadget_usb2_phy_suspend(dwc, false); | ||
2002 | dwc3_gadget_usb3_phy_suspend(dwc, false); | ||
2003 | } | ||
1968 | 2004 | ||
1969 | if (dwc->gadget.speed != USB_SPEED_UNKNOWN) | 2005 | if (dwc->gadget.speed != USB_SPEED_UNKNOWN) |
1970 | dwc3_disconnect_gadget(dwc); | 2006 | dwc3_disconnect_gadget(dwc); |
@@ -2082,8 +2118,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) | |||
2082 | break; | 2118 | break; |
2083 | } | 2119 | } |
2084 | 2120 | ||
2085 | /* Suspend unneded PHY */ | 2121 | /* Recent versions support automatic phy suspend and don't need this */ |
2086 | dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); | 2122 | if (dwc->revision < DWC3_REVISION_194A) { |
2123 | /* Suspend unneeded PHY */ | ||
2124 | dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); | ||
2125 | } | ||
2087 | 2126 | ||
2088 | dep = dwc->eps[0]; | 2127 | dep = dwc->eps[0]; |
2089 | ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); | 2128 | ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); |
@@ -2389,6 +2428,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) | |||
2389 | DWC3_DEVTEN_DISCONNEVTEN); | 2428 | DWC3_DEVTEN_DISCONNEVTEN); |
2390 | dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); | 2429 | dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); |
2391 | 2430 | ||
2431 | /* Enable USB2 LPM and automatic phy suspend only on recent versions */ | ||
2432 | if (dwc->revision >= DWC3_REVISION_194A) { | ||
2433 | reg = dwc3_readl(dwc->regs, DWC3_DCFG); | ||
2434 | reg |= DWC3_DCFG_LPM_CAP; | ||
2435 | dwc3_writel(dwc->regs, DWC3_DCFG, reg); | ||
2436 | |||
2437 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | ||
2438 | reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); | ||
2439 | |||
2440 | /* TODO: This should be configurable */ | ||
2441 | reg |= DWC3_DCTL_HIRD_THRES(31); | ||
2442 | |||
2443 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | ||
2444 | |||
2445 | dwc3_gadget_usb2_phy_suspend(dwc, true); | ||
2446 | dwc3_gadget_usb3_phy_suspend(dwc, true); | ||
2447 | } | ||
2448 | |||
2392 | ret = device_register(&dwc->gadget.dev); | 2449 | ret = device_register(&dwc->gadget.dev); |
2393 | if (ret) { | 2450 | if (ret) { |
2394 | dev_err(dwc->dev, "failed to register gadget device\n"); | 2451 | dev_err(dwc->dev, "failed to register gadget device\n"); |