aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2016-05-31 11:05:15 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-06-01 17:58:59 -0400
commit21f77beece2b6f479648192a87ededd2fb8f1716 (patch)
tree5baa25f6fa776a8bb36b26df4b2be5b24431f9dc
parent517bafffcaf8f882299a74e310082e7b6b2288ad (diff)
usb: musb: Handle cable status better for 2430 glue layer
We may have drivers loaded but no configured gadgets and MUSB may be in host mode. If gadgets are configured during host mode, PM runtime will get confused. Disable PM runtime from gadget state, and do it based on the cable and last state. Note that we may get multiple cable events, so we need to keep track of the power state. Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Bin Liu <b-liu@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/musb/omap2430.c68
1 files changed, 60 insertions, 8 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 3ce94bf3f1c7..fa9932910969 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -49,6 +49,9 @@ struct omap2430_glue {
49 enum musb_vbus_id_status status; 49 enum musb_vbus_id_status status;
50 struct work_struct omap_musb_mailbox_work; 50 struct work_struct omap_musb_mailbox_work;
51 struct device *control_otghs; 51 struct device *control_otghs;
52 bool cable_connected;
53 bool enabled;
54 bool powered;
52}; 55};
53#define glue_to_musb(g) platform_get_drvdata(g->musb) 56#define glue_to_musb(g) platform_get_drvdata(g->musb)
54 57
@@ -234,6 +237,45 @@ static inline void omap2430_low_level_init(struct musb *musb)
234 musb_writel(musb->mregs, OTG_FORCESTDBY, l); 237 musb_writel(musb->mregs, OTG_FORCESTDBY, l);
235} 238}
236 239
240/*
241 * We can get multiple cable events so we need to keep track
242 * of the power state. Only keep power enabled if USB cable is
243 * connected and a gadget is started.
244 */
245static void omap2430_set_power(struct musb *musb, bool enabled, bool cable)
246{
247 struct device *dev = musb->controller;
248 struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
249 bool power_up;
250 int res;
251
252 if (glue->enabled != enabled)
253 glue->enabled = enabled;
254
255 if (glue->cable_connected != cable)
256 glue->cable_connected = cable;
257
258 power_up = glue->enabled && glue->cable_connected;
259 if (power_up == glue->powered) {
260 dev_warn(musb->controller, "power state already %i\n",
261 power_up);
262 return;
263 }
264
265 glue->powered = power_up;
266
267 if (power_up) {
268 res = pm_runtime_get_sync(musb->controller);
269 if (res < 0) {
270 dev_err(musb->controller, "could not enable: %i", res);
271 glue->powered = false;
272 }
273 } else {
274 pm_runtime_mark_last_busy(musb->controller);
275 pm_runtime_put_autosuspend(musb->controller);
276 }
277}
278
237static void omap2430_musb_mailbox(enum musb_vbus_id_status status) 279static void omap2430_musb_mailbox(enum musb_vbus_id_status status)
238{ 280{
239 struct omap2430_glue *glue = _glue; 281 struct omap2430_glue *glue = _glue;
@@ -259,6 +301,13 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
259 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); 301 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
260 struct omap_musb_board_data *data = pdata->board_data; 302 struct omap_musb_board_data *data = pdata->board_data;
261 struct usb_otg *otg = musb->xceiv->otg; 303 struct usb_otg *otg = musb->xceiv->otg;
304 bool cable_connected;
305
306 cable_connected = ((glue->status == MUSB_ID_GROUND) ||
307 (glue->status == MUSB_VBUS_VALID));
308
309 if (cable_connected)
310 omap2430_set_power(musb, glue->enabled, cable_connected);
262 311
263 switch (glue->status) { 312 switch (glue->status) {
264 case MUSB_ID_GROUND: 313 case MUSB_ID_GROUND:
@@ -268,7 +317,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
268 musb->xceiv->otg->state = OTG_STATE_A_IDLE; 317 musb->xceiv->otg->state = OTG_STATE_A_IDLE;
269 musb->xceiv->last_event = USB_EVENT_ID; 318 musb->xceiv->last_event = USB_EVENT_ID;
270 if (musb->gadget_driver) { 319 if (musb->gadget_driver) {
271 pm_runtime_get_sync(dev);
272 omap_control_usb_set_mode(glue->control_otghs, 320 omap_control_usb_set_mode(glue->control_otghs,
273 USB_MODE_HOST); 321 USB_MODE_HOST);
274 omap2430_musb_set_vbus(musb, 1); 322 omap2430_musb_set_vbus(musb, 1);
@@ -281,8 +329,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
281 otg->default_a = false; 329 otg->default_a = false;
282 musb->xceiv->otg->state = OTG_STATE_B_IDLE; 330 musb->xceiv->otg->state = OTG_STATE_B_IDLE;
283 musb->xceiv->last_event = USB_EVENT_VBUS; 331 musb->xceiv->last_event = USB_EVENT_VBUS;
284 if (musb->gadget_driver)
285 pm_runtime_get_sync(dev);
286 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); 332 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
287 break; 333 break;
288 334
@@ -291,11 +337,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
291 dev_dbg(dev, "VBUS Disconnect\n"); 337 dev_dbg(dev, "VBUS Disconnect\n");
292 338
293 musb->xceiv->last_event = USB_EVENT_NONE; 339 musb->xceiv->last_event = USB_EVENT_NONE;
294 if (musb->gadget_driver) { 340 if (musb->gadget_driver)
295 omap2430_musb_set_vbus(musb, 0); 341 omap2430_musb_set_vbus(musb, 0);
296 pm_runtime_mark_last_busy(dev);
297 pm_runtime_put_autosuspend(dev);
298 }
299 342
300 if (data->interface_type == MUSB_INTERFACE_UTMI) 343 if (data->interface_type == MUSB_INTERFACE_UTMI)
301 otg_set_vbus(musb->xceiv->otg, 0); 344 otg_set_vbus(musb->xceiv->otg, 0);
@@ -307,6 +350,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
307 dev_dbg(dev, "ID float\n"); 350 dev_dbg(dev, "ID float\n");
308 } 351 }
309 352
353 if (!cable_connected)
354 omap2430_set_power(musb, glue->enabled, cable_connected);
355
310 atomic_notifier_call_chain(&musb->xceiv->notifier, 356 atomic_notifier_call_chain(&musb->xceiv->notifier,
311 musb->xceiv->last_event, NULL); 357 musb->xceiv->last_event, NULL);
312} 358}
@@ -443,6 +489,8 @@ static void omap2430_musb_enable(struct musb *musb)
443 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); 489 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
444 struct omap_musb_board_data *data = pdata->board_data; 490 struct omap_musb_board_data *data = pdata->board_data;
445 491
492 omap2430_set_power(musb, true, glue->cable_connected);
493
446 switch (glue->status) { 494 switch (glue->status) {
447 495
448 case MUSB_ID_GROUND: 496 case MUSB_ID_GROUND:
@@ -481,6 +529,8 @@ static void omap2430_musb_disable(struct musb *musb)
481 if (glue->status != MUSB_UNKNOWN) 529 if (glue->status != MUSB_UNKNOWN)
482 omap_control_usb_set_mode(glue->control_otghs, 530 omap_control_usb_set_mode(glue->control_otghs,
483 USB_MODE_DISCONNECT); 531 USB_MODE_DISCONNECT);
532
533 omap2430_set_power(musb, false, glue->cable_connected);
484} 534}
485 535
486static int omap2430_musb_exit(struct musb *musb) 536static int omap2430_musb_exit(struct musb *musb)
@@ -653,11 +703,13 @@ err0:
653 703
654static int omap2430_remove(struct platform_device *pdev) 704static int omap2430_remove(struct platform_device *pdev)
655{ 705{
656 struct omap2430_glue *glue = platform_get_drvdata(pdev); 706 struct omap2430_glue *glue = platform_get_drvdata(pdev);
707 struct musb *musb = glue_to_musb(glue);
657 708
658 pm_runtime_get_sync(glue->dev); 709 pm_runtime_get_sync(glue->dev);
659 cancel_work_sync(&glue->omap_musb_mailbox_work); 710 cancel_work_sync(&glue->omap_musb_mailbox_work);
660 platform_device_unregister(glue->musb); 711 platform_device_unregister(glue->musb);
712 omap2430_set_power(musb, false, false);
661 pm_runtime_put_sync(glue->dev); 713 pm_runtime_put_sync(glue->dev);
662 pm_runtime_disable(glue->dev); 714 pm_runtime_disable(glue->dev);
663 715