aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorNeil Zhang <zhangwm@marvell.com>2011-10-12 04:49:39 -0400
committerFelipe Balbi <balbi@ti.com>2011-10-13 13:42:09 -0400
commit1aec033b955ba358dbf365aa7d0bbd49079c8559 (patch)
tree1796c80b618df076cd800dbd8e9f20290513b9be /drivers/usb
parentfb22cbac8242e92d643e5d5cb81bc6307fa6fc9c (diff)
usb: gadget: mv_udc: add clock gating support
This patch is going to support clock gating when vbus detection is posible. Clock and phy will be on only when usb gadget is used(vbus valid). Signed-off-by: Neil Zhang <zhangwm@marvell.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/mv_udc.h7
-rw-r--r--drivers/usb/gadget/mv_udc_core.c189
2 files changed, 185 insertions, 11 deletions
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 3e5e6ea7b0fb..daa75c12f336 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -209,7 +209,12 @@ struct mv_udc {
209 vbus_active:1, 209 vbus_active:1,
210 remote_wakeup:1, 210 remote_wakeup:1,
211 softconnected:1, 211 softconnected:1,
212 force_fs:1; 212 force_fs:1,
213 clock_gating:1,
214 active:1;
215
216 struct work_struct vbus_work;
217 struct workqueue_struct *qwork;
213 218
214 struct mv_usb_platform_data *pdata; 219 struct mv_usb_platform_data *pdata;
215 220
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 333b85b96292..046ab122ee88 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -67,6 +67,7 @@ static struct mv_udc *the_controller;
67int mv_usb_otgsc; 67int mv_usb_otgsc;
68 68
69static void nuke(struct mv_ep *ep, int status); 69static void nuke(struct mv_ep *ep, int status);
70static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
70 71
71/* for endpoint 0 operations */ 72/* for endpoint 0 operations */
72static const struct usb_endpoint_descriptor mv_ep0_desc = { 73static const struct usb_endpoint_descriptor mv_ep0_desc = {
@@ -1133,6 +1134,40 @@ static int udc_reset(struct mv_udc *udc)
1133 return 0; 1134 return 0;
1134} 1135}
1135 1136
1137static int mv_udc_enable(struct mv_udc *udc)
1138{
1139 int retval;
1140
1141 if (udc->clock_gating == 0 || udc->active)
1142 return 0;
1143
1144 dev_dbg(&udc->dev->dev, "enable udc\n");
1145 udc_clock_enable(udc);
1146 if (udc->pdata->phy_init) {
1147 retval = udc->pdata->phy_init(udc->phy_regs);
1148 if (retval) {
1149 dev_err(&udc->dev->dev,
1150 "init phy error %d\n", retval);
1151 udc_clock_disable(udc);
1152 return retval;
1153 }
1154 }
1155 udc->active = 1;
1156
1157 return 0;
1158}
1159
1160static void mv_udc_disable(struct mv_udc *udc)
1161{
1162 if (udc->clock_gating && udc->active) {
1163 dev_dbg(&udc->dev->dev, "disable udc\n");
1164 if (udc->pdata->phy_deinit)
1165 udc->pdata->phy_deinit(udc->phy_regs);
1166 udc_clock_disable(udc);
1167 udc->active = 0;
1168 }
1169}
1170
1136static int mv_udc_get_frame(struct usb_gadget *gadget) 1171static int mv_udc_get_frame(struct usb_gadget *gadget)
1137{ 1172{
1138 struct mv_udc *udc; 1173 struct mv_udc *udc;
@@ -1168,22 +1203,68 @@ static int mv_udc_wakeup(struct usb_gadget *gadget)
1168 return 0; 1203 return 0;
1169} 1204}
1170 1205
1206static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
1207{
1208 struct mv_udc *udc;
1209 unsigned long flags;
1210 int retval = 0;
1211
1212 udc = container_of(gadget, struct mv_udc, gadget);
1213 spin_lock_irqsave(&udc->lock, flags);
1214
1215 dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
1216 __func__, udc->softconnect, udc->vbus_active);
1217
1218 udc->vbus_active = (is_active != 0);
1219 if (udc->driver && udc->softconnect && udc->vbus_active) {
1220 retval = mv_udc_enable(udc);
1221 if (retval == 0) {
1222 /* Clock is disabled, need re-init registers */
1223 udc_reset(udc);
1224 ep0_reset(udc);
1225 udc_start(udc);
1226 }
1227 } else if (udc->driver && udc->softconnect) {
1228 /* stop all the transfer in queue*/
1229 stop_activity(udc, udc->driver);
1230 udc_stop(udc);
1231 mv_udc_disable(udc);
1232 }
1233
1234 spin_unlock_irqrestore(&udc->lock, flags);
1235 return retval;
1236}
1237
1171static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) 1238static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
1172{ 1239{
1173 struct mv_udc *udc; 1240 struct mv_udc *udc;
1174 unsigned long flags; 1241 unsigned long flags;
1242 int retval = 0;
1175 1243
1176 udc = container_of(gadget, struct mv_udc, gadget); 1244 udc = container_of(gadget, struct mv_udc, gadget);
1177 spin_lock_irqsave(&udc->lock, flags); 1245 spin_lock_irqsave(&udc->lock, flags);
1178 1246
1247 dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
1248 __func__, udc->softconnect, udc->vbus_active);
1249
1179 udc->softconnect = (is_on != 0); 1250 udc->softconnect = (is_on != 0);
1180 if (udc->driver && udc->softconnect) 1251 if (udc->driver && udc->softconnect && udc->vbus_active) {
1181 udc_start(udc); 1252 retval = mv_udc_enable(udc);
1182 else 1253 if (retval == 0) {
1254 /* Clock is disabled, need re-init registers */
1255 udc_reset(udc);
1256 ep0_reset(udc);
1257 udc_start(udc);
1258 }
1259 } else if (udc->driver && udc->vbus_active) {
1260 /* stop all the transfer in queue*/
1261 stop_activity(udc, udc->driver);
1183 udc_stop(udc); 1262 udc_stop(udc);
1263 mv_udc_disable(udc);
1264 }
1184 1265
1185 spin_unlock_irqrestore(&udc->lock, flags); 1266 spin_unlock_irqrestore(&udc->lock, flags);
1186 return 0; 1267 return retval;
1187} 1268}
1188 1269
1189static int mv_udc_start(struct usb_gadget_driver *driver, 1270static int mv_udc_start(struct usb_gadget_driver *driver,
@@ -1198,6 +1279,9 @@ static const struct usb_gadget_ops mv_ops = {
1198 /* tries to wake up the host connected to this gadget */ 1279 /* tries to wake up the host connected to this gadget */
1199 .wakeup = mv_udc_wakeup, 1280 .wakeup = mv_udc_wakeup,
1200 1281
1282 /* notify controller that VBUS is powered or not */
1283 .vbus_session = mv_udc_vbus_session,
1284
1201 /* D+ pullup, software-controlled connect/disconnect to USB host */ 1285 /* D+ pullup, software-controlled connect/disconnect to USB host */
1202 .pullup = mv_udc_pullup, 1286 .pullup = mv_udc_pullup,
1203 .start = mv_udc_start, 1287 .start = mv_udc_start,
@@ -1310,7 +1394,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
1310 1394
1311 udc->usb_state = USB_STATE_ATTACHED; 1395 udc->usb_state = USB_STATE_ATTACHED;
1312 udc->ep0_state = WAIT_FOR_SETUP; 1396 udc->ep0_state = WAIT_FOR_SETUP;
1313 udc->ep0_dir = USB_DIR_OUT; 1397 udc->ep0_dir = EP_DIR_OUT;
1314 1398
1315 spin_unlock_irqrestore(&udc->lock, flags); 1399 spin_unlock_irqrestore(&udc->lock, flags);
1316 1400
@@ -1322,9 +1406,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
1322 udc->gadget.dev.driver = NULL; 1406 udc->gadget.dev.driver = NULL;
1323 return retval; 1407 return retval;
1324 } 1408 }
1325 udc_reset(udc); 1409
1326 ep0_reset(udc); 1410 /* pullup is always on */
1327 udc_start(udc); 1411 mv_udc_pullup(&udc->gadget, 1);
1412
1413 /* When boot with cable attached, there will be no vbus irq occurred */
1414 if (udc->qwork)
1415 queue_work(udc->qwork, &udc->vbus_work);
1328 1416
1329 return 0; 1417 return 0;
1330} 1418}
@@ -1337,13 +1425,16 @@ static int mv_udc_stop(struct usb_gadget_driver *driver)
1337 if (!udc) 1425 if (!udc)
1338 return -ENODEV; 1426 return -ENODEV;
1339 1427
1340 udc_stop(udc);
1341
1342 spin_lock_irqsave(&udc->lock, flags); 1428 spin_lock_irqsave(&udc->lock, flags);
1343 1429
1430 mv_udc_enable(udc);
1431 udc_stop(udc);
1432
1344 /* stop all usb activities */ 1433 /* stop all usb activities */
1345 udc->gadget.speed = USB_SPEED_UNKNOWN; 1434 udc->gadget.speed = USB_SPEED_UNKNOWN;
1346 stop_activity(udc, driver); 1435 stop_activity(udc, driver);
1436 mv_udc_disable(udc);
1437
1347 spin_unlock_irqrestore(&udc->lock, flags); 1438 spin_unlock_irqrestore(&udc->lock, flags);
1348 1439
1349 /* unbind gadget driver */ 1440 /* unbind gadget driver */
@@ -1969,6 +2060,35 @@ static irqreturn_t mv_udc_irq(int irq, void *dev)
1969 return IRQ_HANDLED; 2060 return IRQ_HANDLED;
1970} 2061}
1971 2062
2063static irqreturn_t mv_udc_vbus_irq(int irq, void *dev)
2064{
2065 struct mv_udc *udc = (struct mv_udc *)dev;
2066
2067 /* polling VBUS and init phy may cause too much time*/
2068 if (udc->qwork)
2069 queue_work(udc->qwork, &udc->vbus_work);
2070
2071 return IRQ_HANDLED;
2072}
2073
2074static void mv_udc_vbus_work(struct work_struct *work)
2075{
2076 struct mv_udc *udc;
2077 unsigned int vbus;
2078
2079 udc = container_of(work, struct mv_udc, vbus_work);
2080 if (!udc->pdata->vbus)
2081 return;
2082
2083 vbus = udc->pdata->vbus->poll();
2084 dev_info(&udc->dev->dev, "vbus is %d\n", vbus);
2085
2086 if (vbus == VBUS_HIGH)
2087 mv_udc_vbus_session(&udc->gadget, 1);
2088 else if (vbus == VBUS_LOW)
2089 mv_udc_vbus_session(&udc->gadget, 0);
2090}
2091
1972/* release device structure */ 2092/* release device structure */
1973static void gadget_release(struct device *_dev) 2093static void gadget_release(struct device *_dev)
1974{ 2094{
@@ -1984,6 +2104,14 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
1984 2104
1985 usb_del_gadget_udc(&udc->gadget); 2105 usb_del_gadget_udc(&udc->gadget);
1986 2106
2107 if (udc->qwork) {
2108 flush_workqueue(udc->qwork);
2109 destroy_workqueue(udc->qwork);
2110 }
2111
2112 if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
2113 free_irq(udc->pdata->vbus->irq, &dev->dev);
2114
1987 /* free memory allocated in probe */ 2115 /* free memory allocated in probe */
1988 if (udc->dtd_pool) 2116 if (udc->dtd_pool)
1989 dma_pool_destroy(udc->dtd_pool); 2117 dma_pool_destroy(udc->dtd_pool);
@@ -1997,6 +2125,8 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
1997 if (udc->irq) 2125 if (udc->irq)
1998 free_irq(udc->irq, &dev->dev); 2126 free_irq(udc->irq, &dev->dev);
1999 2127
2128 mv_udc_disable(udc);
2129
2000 if (udc->cap_regs) 2130 if (udc->cap_regs)
2001 iounmap(udc->cap_regs); 2131 iounmap(udc->cap_regs);
2002 udc->cap_regs = NULL; 2132 udc->cap_regs = NULL;
@@ -2197,13 +2327,52 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
2197 2327
2198 eps_init(udc); 2328 eps_init(udc);
2199 2329
2330 /* VBUS detect: we can disable/enable clock on demand.*/
2331 if (pdata->vbus) {
2332 udc->clock_gating = 1;
2333 retval = request_threaded_irq(pdata->vbus->irq, NULL,
2334 mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
2335 if (retval) {
2336 dev_info(&dev->dev,
2337 "Can not request irq for VBUS, "
2338 "disable clock gating\n");
2339 udc->clock_gating = 0;
2340 }
2341
2342 udc->qwork = create_singlethread_workqueue("mv_udc_queue");
2343 if (!udc->qwork) {
2344 dev_err(&dev->dev, "cannot create workqueue\n");
2345 retval = -ENOMEM;
2346 goto err_unregister;
2347 }
2348
2349 INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
2350 }
2351
2352 /*
2353 * When clock gating is supported, we can disable clk and phy.
2354 * If not, it means that VBUS detection is not supported, we
2355 * have to enable vbus active all the time to let controller work.
2356 */
2357 if (udc->clock_gating) {
2358 if (udc->pdata->phy_deinit)
2359 udc->pdata->phy_deinit(udc->phy_regs);
2360 udc_clock_disable(udc);
2361 } else
2362 udc->vbus_active = 1;
2363
2200 retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); 2364 retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
2201 if (retval) 2365 if (retval)
2202 goto err_unregister; 2366 goto err_unregister;
2203 2367
2368 dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n",
2369 udc->clock_gating ? "with" : "without");
2370
2204 return 0; 2371 return 0;
2205 2372
2206err_unregister: 2373err_unregister:
2374 if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
2375 free_irq(pdata->vbus->irq, &dev->dev);
2207 device_unregister(&udc->gadget.dev); 2376 device_unregister(&udc->gadget.dev);
2208err_free_irq: 2377err_free_irq:
2209 free_irq(udc->irq, &dev->dev); 2378 free_irq(udc->irq, &dev->dev);