diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-05 18:35:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-05 18:35:41 -0400 |
commit | ff9cce82772a78983b529e044d85884d3ec95fda (patch) | |
tree | 6491adac0538739a415f7b776d1865ce7ae5d1f7 /drivers/usb/musb/omap2430.c | |
parent | 933141509cefd64102a943d61d154c5c53bad889 (diff) | |
parent | f8ecf829481b2cc7301a811da9d2df53ef174977 (diff) |
Merge tag 'xceiv-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
usb: phy: patches for v3.6 merge window
We are starting to support multiple USB phys as
we should thanks for Kishon's work. DeviceTree support
for USB PHYs won't come until discussion with DeviceTree
maintainer is finished.
Together with that series, we have one fix for twl4030
which missed a IRQF_ONESHOT annotation when requesting
a threaded IRQ without a top half handler, and removal
of an unused variable compilation warning to isp1301_omap.
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r-- | drivers/usb/musb/omap2430.c | 124 |
1 files changed, 77 insertions, 47 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index c7785e81254c..5fdb9da8dd56 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/dma-mapping.h> | 34 | #include <linux/dma-mapping.h> |
35 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
36 | #include <linux/err.h> | 36 | #include <linux/err.h> |
37 | #include <linux/usb/musb-omap.h> | ||
37 | 38 | ||
38 | #include "musb_core.h" | 39 | #include "musb_core.h" |
39 | #include "omap2430.h" | 40 | #include "omap2430.h" |
@@ -41,9 +42,13 @@ | |||
41 | struct omap2430_glue { | 42 | struct omap2430_glue { |
42 | struct device *dev; | 43 | struct device *dev; |
43 | struct platform_device *musb; | 44 | struct platform_device *musb; |
45 | enum omap_musb_vbus_id_status status; | ||
46 | struct work_struct omap_musb_mailbox_work; | ||
44 | }; | 47 | }; |
45 | #define glue_to_musb(g) platform_get_drvdata(g->musb) | 48 | #define glue_to_musb(g) platform_get_drvdata(g->musb) |
46 | 49 | ||
50 | struct omap2430_glue *_glue; | ||
51 | |||
47 | static struct timer_list musb_idle_timer; | 52 | static struct timer_list musb_idle_timer; |
48 | 53 | ||
49 | static void musb_do_idle(unsigned long _musb) | 54 | static void musb_do_idle(unsigned long _musb) |
@@ -223,50 +228,63 @@ static inline void omap2430_low_level_init(struct musb *musb) | |||
223 | musb_writel(musb->mregs, OTG_FORCESTDBY, l); | 228 | musb_writel(musb->mregs, OTG_FORCESTDBY, l); |
224 | } | 229 | } |
225 | 230 | ||
226 | static int musb_otg_notifications(struct notifier_block *nb, | 231 | void omap_musb_mailbox(enum omap_musb_vbus_id_status status) |
227 | unsigned long event, void *unused) | ||
228 | { | 232 | { |
229 | struct musb *musb = container_of(nb, struct musb, nb); | 233 | struct omap2430_glue *glue = _glue; |
234 | struct musb *musb = glue_to_musb(glue); | ||
230 | 235 | ||
231 | musb->xceiv_event = event; | 236 | glue->status = status; |
232 | schedule_work(&musb->otg_notifier_work); | 237 | if (!musb) { |
238 | dev_err(glue->dev, "musb core is not yet ready\n"); | ||
239 | return; | ||
240 | } | ||
233 | 241 | ||
234 | return NOTIFY_OK; | 242 | schedule_work(&glue->omap_musb_mailbox_work); |
235 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(omap_musb_mailbox); | ||
236 | 245 | ||
237 | static void musb_otg_notifier_work(struct work_struct *data_notifier_work) | 246 | static void omap_musb_set_mailbox(struct omap2430_glue *glue) |
238 | { | 247 | { |
239 | struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work); | 248 | struct musb *musb = glue_to_musb(glue); |
240 | struct device *dev = musb->controller; | 249 | struct device *dev = musb->controller; |
241 | struct musb_hdrc_platform_data *pdata = dev->platform_data; | 250 | struct musb_hdrc_platform_data *pdata = dev->platform_data; |
242 | struct omap_musb_board_data *data = pdata->board_data; | 251 | struct omap_musb_board_data *data = pdata->board_data; |
252 | struct usb_otg *otg = musb->xceiv->otg; | ||
243 | 253 | ||
244 | switch (musb->xceiv_event) { | 254 | switch (glue->status) { |
245 | case USB_EVENT_ID: | 255 | case OMAP_MUSB_ID_GROUND: |
246 | dev_dbg(musb->controller, "ID GND\n"); | 256 | dev_dbg(dev, "ID GND\n"); |
247 | 257 | ||
258 | otg->default_a = true; | ||
259 | musb->xceiv->state = OTG_STATE_A_IDLE; | ||
260 | musb->xceiv->last_event = USB_EVENT_ID; | ||
248 | if (!is_otg_enabled(musb) || musb->gadget_driver) { | 261 | if (!is_otg_enabled(musb) || musb->gadget_driver) { |
249 | pm_runtime_get_sync(musb->controller); | 262 | pm_runtime_get_sync(dev); |
250 | usb_phy_init(musb->xceiv); | 263 | usb_phy_init(musb->xceiv); |
251 | omap2430_musb_set_vbus(musb, 1); | 264 | omap2430_musb_set_vbus(musb, 1); |
252 | } | 265 | } |
253 | break; | 266 | break; |
254 | 267 | ||
255 | case USB_EVENT_VBUS: | 268 | case OMAP_MUSB_VBUS_VALID: |
256 | dev_dbg(musb->controller, "VBUS Connect\n"); | 269 | dev_dbg(dev, "VBUS Connect\n"); |
257 | 270 | ||
271 | otg->default_a = false; | ||
272 | musb->xceiv->state = OTG_STATE_B_IDLE; | ||
273 | musb->xceiv->last_event = USB_EVENT_VBUS; | ||
258 | if (musb->gadget_driver) | 274 | if (musb->gadget_driver) |
259 | pm_runtime_get_sync(musb->controller); | 275 | pm_runtime_get_sync(dev); |
260 | usb_phy_init(musb->xceiv); | 276 | usb_phy_init(musb->xceiv); |
261 | break; | 277 | break; |
262 | 278 | ||
263 | case USB_EVENT_NONE: | 279 | case OMAP_MUSB_ID_FLOAT: |
264 | dev_dbg(musb->controller, "VBUS Disconnect\n"); | 280 | case OMAP_MUSB_VBUS_OFF: |
281 | dev_dbg(dev, "VBUS Disconnect\n"); | ||
265 | 282 | ||
283 | musb->xceiv->last_event = USB_EVENT_NONE; | ||
266 | if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) | 284 | if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) |
267 | if (musb->gadget_driver) { | 285 | if (musb->gadget_driver) { |
268 | pm_runtime_mark_last_busy(musb->controller); | 286 | pm_runtime_mark_last_busy(dev); |
269 | pm_runtime_put_autosuspend(musb->controller); | 287 | pm_runtime_put_autosuspend(dev); |
270 | } | 288 | } |
271 | 289 | ||
272 | if (data->interface_type == MUSB_INTERFACE_UTMI) { | 290 | if (data->interface_type == MUSB_INTERFACE_UTMI) { |
@@ -276,15 +294,24 @@ static void musb_otg_notifier_work(struct work_struct *data_notifier_work) | |||
276 | usb_phy_shutdown(musb->xceiv); | 294 | usb_phy_shutdown(musb->xceiv); |
277 | break; | 295 | break; |
278 | default: | 296 | default: |
279 | dev_dbg(musb->controller, "ID float\n"); | 297 | dev_dbg(dev, "ID float\n"); |
280 | } | 298 | } |
281 | } | 299 | } |
282 | 300 | ||
301 | |||
302 | static void omap_musb_mailbox_work(struct work_struct *mailbox_work) | ||
303 | { | ||
304 | struct omap2430_glue *glue = container_of(mailbox_work, | ||
305 | struct omap2430_glue, omap_musb_mailbox_work); | ||
306 | omap_musb_set_mailbox(glue); | ||
307 | } | ||
308 | |||
283 | static int omap2430_musb_init(struct musb *musb) | 309 | static int omap2430_musb_init(struct musb *musb) |
284 | { | 310 | { |
285 | u32 l; | 311 | u32 l; |
286 | int status = 0; | 312 | int status = 0; |
287 | struct device *dev = musb->controller; | 313 | struct device *dev = musb->controller; |
314 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
288 | struct musb_hdrc_platform_data *plat = dev->platform_data; | 315 | struct musb_hdrc_platform_data *plat = dev->platform_data; |
289 | struct omap_musb_board_data *data = plat->board_data; | 316 | struct omap_musb_board_data *data = plat->board_data; |
290 | 317 | ||
@@ -292,14 +319,12 @@ static int omap2430_musb_init(struct musb *musb) | |||
292 | * up through ULPI. TWL4030-family PMICs include one, | 319 | * up through ULPI. TWL4030-family PMICs include one, |
293 | * which needs a driver, drivers aren't always needed. | 320 | * which needs a driver, drivers aren't always needed. |
294 | */ | 321 | */ |
295 | musb->xceiv = usb_get_transceiver(); | 322 | musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); |
296 | if (!musb->xceiv) { | 323 | if (IS_ERR_OR_NULL(musb->xceiv)) { |
297 | pr_err("HS USB OTG: no transceiver configured\n"); | 324 | pr_err("HS USB OTG: no transceiver configured\n"); |
298 | return -ENODEV; | 325 | return -ENODEV; |
299 | } | 326 | } |
300 | 327 | ||
301 | INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work); | ||
302 | |||
303 | status = pm_runtime_get_sync(dev); | 328 | status = pm_runtime_get_sync(dev); |
304 | if (status < 0) { | 329 | if (status < 0) { |
305 | dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); | 330 | dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); |
@@ -326,14 +351,11 @@ static int omap2430_musb_init(struct musb *musb) | |||
326 | musb_readl(musb->mregs, OTG_INTERFSEL), | 351 | musb_readl(musb->mregs, OTG_INTERFSEL), |
327 | musb_readl(musb->mregs, OTG_SIMENABLE)); | 352 | musb_readl(musb->mregs, OTG_SIMENABLE)); |
328 | 353 | ||
329 | musb->nb.notifier_call = musb_otg_notifications; | ||
330 | status = usb_register_notifier(musb->xceiv, &musb->nb); | ||
331 | |||
332 | if (status) | ||
333 | dev_dbg(musb->controller, "notification register failed\n"); | ||
334 | |||
335 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); | 354 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); |
336 | 355 | ||
356 | if (glue->status != OMAP_MUSB_UNKNOWN) | ||
357 | omap_musb_set_mailbox(glue); | ||
358 | |||
337 | pm_runtime_put_noidle(musb->controller); | 359 | pm_runtime_put_noidle(musb->controller); |
338 | return 0; | 360 | return 0; |
339 | 361 | ||
@@ -346,12 +368,13 @@ static void omap2430_musb_enable(struct musb *musb) | |||
346 | u8 devctl; | 368 | u8 devctl; |
347 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | 369 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); |
348 | struct device *dev = musb->controller; | 370 | struct device *dev = musb->controller; |
371 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
349 | struct musb_hdrc_platform_data *pdata = dev->platform_data; | 372 | struct musb_hdrc_platform_data *pdata = dev->platform_data; |
350 | struct omap_musb_board_data *data = pdata->board_data; | 373 | struct omap_musb_board_data *data = pdata->board_data; |
351 | 374 | ||
352 | switch (musb->xceiv->last_event) { | 375 | switch (glue->status) { |
353 | 376 | ||
354 | case USB_EVENT_ID: | 377 | case OMAP_MUSB_ID_GROUND: |
355 | usb_phy_init(musb->xceiv); | 378 | usb_phy_init(musb->xceiv); |
356 | if (data->interface_type != MUSB_INTERFACE_UTMI) | 379 | if (data->interface_type != MUSB_INTERFACE_UTMI) |
357 | break; | 380 | break; |
@@ -370,7 +393,7 @@ static void omap2430_musb_enable(struct musb *musb) | |||
370 | } | 393 | } |
371 | break; | 394 | break; |
372 | 395 | ||
373 | case USB_EVENT_VBUS: | 396 | case OMAP_MUSB_VBUS_VALID: |
374 | usb_phy_init(musb->xceiv); | 397 | usb_phy_init(musb->xceiv); |
375 | break; | 398 | break; |
376 | 399 | ||
@@ -381,17 +404,18 @@ static void omap2430_musb_enable(struct musb *musb) | |||
381 | 404 | ||
382 | static void omap2430_musb_disable(struct musb *musb) | 405 | static void omap2430_musb_disable(struct musb *musb) |
383 | { | 406 | { |
384 | if (musb->xceiv->last_event) | 407 | struct device *dev = musb->controller; |
408 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
409 | |||
410 | if (glue->status != OMAP_MUSB_UNKNOWN) | ||
385 | usb_phy_shutdown(musb->xceiv); | 411 | usb_phy_shutdown(musb->xceiv); |
386 | } | 412 | } |
387 | 413 | ||
388 | static int omap2430_musb_exit(struct musb *musb) | 414 | static int omap2430_musb_exit(struct musb *musb) |
389 | { | 415 | { |
390 | del_timer_sync(&musb_idle_timer); | 416 | del_timer_sync(&musb_idle_timer); |
391 | cancel_work_sync(&musb->otg_notifier_work); | ||
392 | 417 | ||
393 | omap2430_low_level_exit(musb); | 418 | omap2430_low_level_exit(musb); |
394 | usb_put_transceiver(musb->xceiv); | ||
395 | 419 | ||
396 | return 0; | 420 | return 0; |
397 | } | 421 | } |
@@ -418,7 +442,7 @@ static int __devinit omap2430_probe(struct platform_device *pdev) | |||
418 | struct omap2430_glue *glue; | 442 | struct omap2430_glue *glue; |
419 | int ret = -ENOMEM; | 443 | int ret = -ENOMEM; |
420 | 444 | ||
421 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | 445 | glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); |
422 | if (!glue) { | 446 | if (!glue) { |
423 | dev_err(&pdev->dev, "failed to allocate glue context\n"); | 447 | dev_err(&pdev->dev, "failed to allocate glue context\n"); |
424 | goto err0; | 448 | goto err0; |
@@ -427,7 +451,7 @@ static int __devinit omap2430_probe(struct platform_device *pdev) | |||
427 | musb = platform_device_alloc("musb-hdrc", -1); | 451 | musb = platform_device_alloc("musb-hdrc", -1); |
428 | if (!musb) { | 452 | if (!musb) { |
429 | dev_err(&pdev->dev, "failed to allocate musb device\n"); | 453 | dev_err(&pdev->dev, "failed to allocate musb device\n"); |
430 | goto err1; | 454 | goto err0; |
431 | } | 455 | } |
432 | 456 | ||
433 | musb->dev.parent = &pdev->dev; | 457 | musb->dev.parent = &pdev->dev; |
@@ -436,22 +460,31 @@ static int __devinit omap2430_probe(struct platform_device *pdev) | |||
436 | 460 | ||
437 | glue->dev = &pdev->dev; | 461 | glue->dev = &pdev->dev; |
438 | glue->musb = musb; | 462 | glue->musb = musb; |
463 | glue->status = OMAP_MUSB_UNKNOWN; | ||
439 | 464 | ||
440 | pdata->platform_ops = &omap2430_ops; | 465 | pdata->platform_ops = &omap2430_ops; |
441 | 466 | ||
442 | platform_set_drvdata(pdev, glue); | 467 | platform_set_drvdata(pdev, glue); |
443 | 468 | ||
469 | /* | ||
470 | * REVISIT if we ever have two instances of the wrapper, we will be | ||
471 | * in big trouble | ||
472 | */ | ||
473 | _glue = glue; | ||
474 | |||
475 | INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work); | ||
476 | |||
444 | ret = platform_device_add_resources(musb, pdev->resource, | 477 | ret = platform_device_add_resources(musb, pdev->resource, |
445 | pdev->num_resources); | 478 | pdev->num_resources); |
446 | if (ret) { | 479 | if (ret) { |
447 | dev_err(&pdev->dev, "failed to add resources\n"); | 480 | dev_err(&pdev->dev, "failed to add resources\n"); |
448 | goto err2; | 481 | goto err1; |
449 | } | 482 | } |
450 | 483 | ||
451 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); | 484 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); |
452 | if (ret) { | 485 | if (ret) { |
453 | dev_err(&pdev->dev, "failed to add platform_data\n"); | 486 | dev_err(&pdev->dev, "failed to add platform_data\n"); |
454 | goto err2; | 487 | goto err1; |
455 | } | 488 | } |
456 | 489 | ||
457 | pm_runtime_enable(&pdev->dev); | 490 | pm_runtime_enable(&pdev->dev); |
@@ -459,16 +492,13 @@ static int __devinit omap2430_probe(struct platform_device *pdev) | |||
459 | ret = platform_device_add(musb); | 492 | ret = platform_device_add(musb); |
460 | if (ret) { | 493 | if (ret) { |
461 | dev_err(&pdev->dev, "failed to register musb device\n"); | 494 | dev_err(&pdev->dev, "failed to register musb device\n"); |
462 | goto err2; | 495 | goto err1; |
463 | } | 496 | } |
464 | 497 | ||
465 | return 0; | 498 | return 0; |
466 | 499 | ||
467 | err2: | ||
468 | platform_device_put(musb); | ||
469 | |||
470 | err1: | 500 | err1: |
471 | kfree(glue); | 501 | platform_device_put(musb); |
472 | 502 | ||
473 | err0: | 503 | err0: |
474 | return ret; | 504 | return ret; |
@@ -478,9 +508,9 @@ static int __devexit omap2430_remove(struct platform_device *pdev) | |||
478 | { | 508 | { |
479 | struct omap2430_glue *glue = platform_get_drvdata(pdev); | 509 | struct omap2430_glue *glue = platform_get_drvdata(pdev); |
480 | 510 | ||
511 | cancel_work_sync(&glue->omap_musb_mailbox_work); | ||
481 | platform_device_del(glue->musb); | 512 | platform_device_del(glue->musb); |
482 | platform_device_put(glue->musb); | 513 | platform_device_put(glue->musb); |
483 | kfree(glue); | ||
484 | 514 | ||
485 | return 0; | 515 | return 0; |
486 | } | 516 | } |
@@ -546,7 +576,7 @@ static int __init omap2430_init(void) | |||
546 | { | 576 | { |
547 | return platform_driver_register(&omap2430_driver); | 577 | return platform_driver_register(&omap2430_driver); |
548 | } | 578 | } |
549 | module_init(omap2430_init); | 579 | subsys_initcall(omap2430_init); |
550 | 580 | ||
551 | static void __exit omap2430_exit(void) | 581 | static void __exit omap2430_exit(void) |
552 | { | 582 | { |