diff options
-rw-r--r-- | drivers/usb/musb/omap2430.c | 94 | ||||
-rw-r--r-- | drivers/usb/otg/twl4030-usb.c | 46 | ||||
-rw-r--r-- | drivers/usb/otg/twl6030-usb.c | 47 | ||||
-rw-r--r-- | include/linux/usb/musb-omap.h | 30 |
4 files changed, 133 insertions, 84 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index f40c8053a291..063687085d1e 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,11 +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; |
44 | u8 xceiv_event; | 45 | enum omap_musb_vbus_id_status status; |
45 | struct work_struct omap_musb_mailbox_work; | 46 | struct work_struct omap_musb_mailbox_work; |
46 | }; | 47 | }; |
47 | #define glue_to_musb(g) platform_get_drvdata(g->musb) | 48 | #define glue_to_musb(g) platform_get_drvdata(g->musb) |
48 | 49 | ||
50 | struct omap2430_glue *_glue; | ||
51 | |||
49 | static struct timer_list musb_idle_timer; | 52 | static struct timer_list musb_idle_timer; |
50 | 53 | ||
51 | static void musb_do_idle(unsigned long _musb) | 54 | static void musb_do_idle(unsigned long _musb) |
@@ -225,54 +228,58 @@ static inline void omap2430_low_level_init(struct musb *musb) | |||
225 | musb_writel(musb->mregs, OTG_FORCESTDBY, l); | 228 | musb_writel(musb->mregs, OTG_FORCESTDBY, l); |
226 | } | 229 | } |
227 | 230 | ||
228 | static int musb_otg_notifications(struct notifier_block *nb, | 231 | void omap_musb_mailbox(enum omap_musb_vbus_id_status status) |
229 | unsigned long event, void *unused) | ||
230 | { | 232 | { |
231 | struct musb *musb = container_of(nb, struct musb, nb); | 233 | struct omap2430_glue *glue = _glue; |
232 | struct device *dev = musb->controller; | 234 | struct musb *musb = glue_to_musb(glue); |
233 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
234 | 235 | ||
235 | glue->xceiv_event = event; | 236 | glue->status = status; |
236 | schedule_work(&glue->omap_musb_mailbox_work); | 237 | if (!musb) { |
238 | dev_err(glue->dev, "musb core is not yet ready\n"); | ||
239 | return; | ||
240 | } | ||
237 | 241 | ||
238 | return NOTIFY_OK; | 242 | schedule_work(&glue->omap_musb_mailbox_work); |
239 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(omap_musb_mailbox); | ||
240 | 245 | ||
241 | static void omap_musb_mailbox_work(struct work_struct *data_notifier_work) | 246 | static void omap_musb_set_mailbox(struct omap2430_glue *glue) |
242 | { | 247 | { |
243 | struct omap2430_glue *glue = container_of(data_notifier_work, | ||
244 | struct omap2430_glue, omap_musb_mailbox_work); | ||
245 | struct musb *musb = glue_to_musb(glue); | 248 | struct musb *musb = glue_to_musb(glue); |
246 | struct device *dev = musb->controller; | 249 | struct device *dev = musb->controller; |
247 | struct musb_hdrc_platform_data *pdata = dev->platform_data; | 250 | struct musb_hdrc_platform_data *pdata = dev->platform_data; |
248 | struct omap_musb_board_data *data = pdata->board_data; | 251 | struct omap_musb_board_data *data = pdata->board_data; |
249 | 252 | ||
250 | switch (glue->xceiv_event) { | 253 | switch (glue->status) { |
251 | case USB_EVENT_ID: | 254 | case OMAP_MUSB_ID_GROUND: |
252 | dev_dbg(musb->controller, "ID GND\n"); | 255 | dev_dbg(dev, "ID GND\n"); |
253 | 256 | ||
257 | musb->xceiv->last_event = USB_EVENT_ID; | ||
254 | if (!is_otg_enabled(musb) || musb->gadget_driver) { | 258 | if (!is_otg_enabled(musb) || musb->gadget_driver) { |
255 | pm_runtime_get_sync(musb->controller); | 259 | pm_runtime_get_sync(dev); |
256 | usb_phy_init(musb->xceiv); | 260 | usb_phy_init(musb->xceiv); |
257 | omap2430_musb_set_vbus(musb, 1); | 261 | omap2430_musb_set_vbus(musb, 1); |
258 | } | 262 | } |
259 | break; | 263 | break; |
260 | 264 | ||
261 | case USB_EVENT_VBUS: | 265 | case OMAP_MUSB_VBUS_VALID: |
262 | dev_dbg(musb->controller, "VBUS Connect\n"); | 266 | dev_dbg(dev, "VBUS Connect\n"); |
263 | 267 | ||
268 | musb->xceiv->last_event = USB_EVENT_VBUS; | ||
264 | if (musb->gadget_driver) | 269 | if (musb->gadget_driver) |
265 | pm_runtime_get_sync(musb->controller); | 270 | pm_runtime_get_sync(dev); |
266 | usb_phy_init(musb->xceiv); | 271 | usb_phy_init(musb->xceiv); |
267 | break; | 272 | break; |
268 | 273 | ||
269 | case USB_EVENT_NONE: | 274 | case OMAP_MUSB_ID_FLOAT: |
270 | dev_dbg(musb->controller, "VBUS Disconnect\n"); | 275 | case OMAP_MUSB_VBUS_OFF: |
276 | dev_dbg(dev, "VBUS Disconnect\n"); | ||
271 | 277 | ||
278 | musb->xceiv->last_event = USB_EVENT_NONE; | ||
272 | if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) | 279 | if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) |
273 | if (musb->gadget_driver) { | 280 | if (musb->gadget_driver) { |
274 | pm_runtime_mark_last_busy(musb->controller); | 281 | pm_runtime_mark_last_busy(dev); |
275 | pm_runtime_put_autosuspend(musb->controller); | 282 | pm_runtime_put_autosuspend(dev); |
276 | } | 283 | } |
277 | 284 | ||
278 | if (data->interface_type == MUSB_INTERFACE_UTMI) { | 285 | if (data->interface_type == MUSB_INTERFACE_UTMI) { |
@@ -282,15 +289,24 @@ static void omap_musb_mailbox_work(struct work_struct *data_notifier_work) | |||
282 | usb_phy_shutdown(musb->xceiv); | 289 | usb_phy_shutdown(musb->xceiv); |
283 | break; | 290 | break; |
284 | default: | 291 | default: |
285 | dev_dbg(musb->controller, "ID float\n"); | 292 | dev_dbg(dev, "ID float\n"); |
286 | } | 293 | } |
287 | } | 294 | } |
288 | 295 | ||
296 | |||
297 | static void omap_musb_mailbox_work(struct work_struct *mailbox_work) | ||
298 | { | ||
299 | struct omap2430_glue *glue = container_of(mailbox_work, | ||
300 | struct omap2430_glue, omap_musb_mailbox_work); | ||
301 | omap_musb_set_mailbox(glue); | ||
302 | } | ||
303 | |||
289 | static int omap2430_musb_init(struct musb *musb) | 304 | static int omap2430_musb_init(struct musb *musb) |
290 | { | 305 | { |
291 | u32 l; | 306 | u32 l; |
292 | int status = 0; | 307 | int status = 0; |
293 | struct device *dev = musb->controller; | 308 | struct device *dev = musb->controller; |
309 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
294 | struct musb_hdrc_platform_data *plat = dev->platform_data; | 310 | struct musb_hdrc_platform_data *plat = dev->platform_data; |
295 | struct omap_musb_board_data *data = plat->board_data; | 311 | struct omap_musb_board_data *data = plat->board_data; |
296 | 312 | ||
@@ -330,14 +346,11 @@ static int omap2430_musb_init(struct musb *musb) | |||
330 | musb_readl(musb->mregs, OTG_INTERFSEL), | 346 | musb_readl(musb->mregs, OTG_INTERFSEL), |
331 | musb_readl(musb->mregs, OTG_SIMENABLE)); | 347 | musb_readl(musb->mregs, OTG_SIMENABLE)); |
332 | 348 | ||
333 | musb->nb.notifier_call = musb_otg_notifications; | ||
334 | status = usb_register_notifier(musb->xceiv, &musb->nb); | ||
335 | |||
336 | if (status) | ||
337 | dev_dbg(musb->controller, "notification register failed\n"); | ||
338 | |||
339 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); | 349 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); |
340 | 350 | ||
351 | if (glue->status != OMAP_MUSB_UNKNOWN) | ||
352 | omap_musb_set_mailbox(glue); | ||
353 | |||
341 | pm_runtime_put_noidle(musb->controller); | 354 | pm_runtime_put_noidle(musb->controller); |
342 | return 0; | 355 | return 0; |
343 | 356 | ||
@@ -350,12 +363,13 @@ static void omap2430_musb_enable(struct musb *musb) | |||
350 | u8 devctl; | 363 | u8 devctl; |
351 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | 364 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); |
352 | struct device *dev = musb->controller; | 365 | struct device *dev = musb->controller; |
366 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
353 | struct musb_hdrc_platform_data *pdata = dev->platform_data; | 367 | struct musb_hdrc_platform_data *pdata = dev->platform_data; |
354 | struct omap_musb_board_data *data = pdata->board_data; | 368 | struct omap_musb_board_data *data = pdata->board_data; |
355 | 369 | ||
356 | switch (musb->xceiv->last_event) { | 370 | switch (glue->status) { |
357 | 371 | ||
358 | case USB_EVENT_ID: | 372 | case OMAP_MUSB_ID_GROUND: |
359 | usb_phy_init(musb->xceiv); | 373 | usb_phy_init(musb->xceiv); |
360 | if (data->interface_type != MUSB_INTERFACE_UTMI) | 374 | if (data->interface_type != MUSB_INTERFACE_UTMI) |
361 | break; | 375 | break; |
@@ -374,7 +388,7 @@ static void omap2430_musb_enable(struct musb *musb) | |||
374 | } | 388 | } |
375 | break; | 389 | break; |
376 | 390 | ||
377 | case USB_EVENT_VBUS: | 391 | case OMAP_MUSB_VBUS_VALID: |
378 | usb_phy_init(musb->xceiv); | 392 | usb_phy_init(musb->xceiv); |
379 | break; | 393 | break; |
380 | 394 | ||
@@ -385,7 +399,10 @@ static void omap2430_musb_enable(struct musb *musb) | |||
385 | 399 | ||
386 | static void omap2430_musb_disable(struct musb *musb) | 400 | static void omap2430_musb_disable(struct musb *musb) |
387 | { | 401 | { |
388 | if (musb->xceiv->last_event) | 402 | struct device *dev = musb->controller; |
403 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | ||
404 | |||
405 | if (glue->status != OMAP_MUSB_UNKNOWN) | ||
389 | usb_phy_shutdown(musb->xceiv); | 406 | usb_phy_shutdown(musb->xceiv); |
390 | } | 407 | } |
391 | 408 | ||
@@ -439,11 +456,18 @@ static int __devinit omap2430_probe(struct platform_device *pdev) | |||
439 | 456 | ||
440 | glue->dev = &pdev->dev; | 457 | glue->dev = &pdev->dev; |
441 | glue->musb = musb; | 458 | glue->musb = musb; |
459 | glue->status = OMAP_MUSB_UNKNOWN; | ||
442 | 460 | ||
443 | pdata->platform_ops = &omap2430_ops; | 461 | pdata->platform_ops = &omap2430_ops; |
444 | 462 | ||
445 | platform_set_drvdata(pdev, glue); | 463 | platform_set_drvdata(pdev, glue); |
446 | 464 | ||
465 | /* | ||
466 | * REVISIT if we ever have two instances of the wrapper, we will be | ||
467 | * in big trouble | ||
468 | */ | ||
469 | _glue = glue; | ||
470 | |||
447 | INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work); | 471 | INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work); |
448 | 472 | ||
449 | ret = platform_device_add_resources(musb, pdev->resource, | 473 | ret = platform_device_add_resources(musb, pdev->resource, |
@@ -552,7 +576,7 @@ static int __init omap2430_init(void) | |||
552 | { | 576 | { |
553 | return platform_driver_register(&omap2430_driver); | 577 | return platform_driver_register(&omap2430_driver); |
554 | } | 578 | } |
555 | module_init(omap2430_init); | 579 | subsys_initcall(omap2430_init); |
556 | 580 | ||
557 | static void __exit omap2430_exit(void) | 581 | static void __exit omap2430_exit(void) |
558 | { | 582 | { |
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 25a09fabbe35..a7b809e217ea 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c | |||
@@ -33,11 +33,11 @@ | |||
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/usb/otg.h> | 35 | #include <linux/usb/otg.h> |
36 | #include <linux/usb/musb-omap.h> | ||
36 | #include <linux/usb/ulpi.h> | 37 | #include <linux/usb/ulpi.h> |
37 | #include <linux/i2c/twl.h> | 38 | #include <linux/i2c/twl.h> |
38 | #include <linux/regulator/consumer.h> | 39 | #include <linux/regulator/consumer.h> |
39 | #include <linux/err.h> | 40 | #include <linux/err.h> |
40 | #include <linux/notifier.h> | ||
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | 42 | ||
43 | /* Register defines */ | 43 | /* Register defines */ |
@@ -159,7 +159,7 @@ struct twl4030_usb { | |||
159 | enum twl4030_usb_mode usb_mode; | 159 | enum twl4030_usb_mode usb_mode; |
160 | 160 | ||
161 | int irq; | 161 | int irq; |
162 | u8 linkstat; | 162 | enum omap_musb_vbus_id_status linkstat; |
163 | bool vbus_supplied; | 163 | bool vbus_supplied; |
164 | u8 asleep; | 164 | u8 asleep; |
165 | bool irq_enabled; | 165 | bool irq_enabled; |
@@ -246,10 +246,11 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) | |||
246 | 246 | ||
247 | /*-------------------------------------------------------------------------*/ | 247 | /*-------------------------------------------------------------------------*/ |
248 | 248 | ||
249 | static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl) | 249 | static enum omap_musb_vbus_id_status |
250 | twl4030_usb_linkstat(struct twl4030_usb *twl) | ||
250 | { | 251 | { |
251 | int status; | 252 | int status; |
252 | int linkstat = USB_EVENT_NONE; | 253 | enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN; |
253 | struct usb_otg *otg = twl->phy.otg; | 254 | struct usb_otg *otg = twl->phy.otg; |
254 | 255 | ||
255 | twl->vbus_supplied = false; | 256 | twl->vbus_supplied = false; |
@@ -273,24 +274,24 @@ static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl) | |||
273 | twl->vbus_supplied = true; | 274 | twl->vbus_supplied = true; |
274 | 275 | ||
275 | if (status & BIT(2)) | 276 | if (status & BIT(2)) |
276 | linkstat = USB_EVENT_ID; | 277 | linkstat = OMAP_MUSB_ID_GROUND; |
277 | else | 278 | else |
278 | linkstat = USB_EVENT_VBUS; | 279 | linkstat = OMAP_MUSB_VBUS_VALID; |
279 | } else | 280 | } else { |
280 | linkstat = USB_EVENT_NONE; | 281 | if (twl->linkstat != OMAP_MUSB_UNKNOWN) |
282 | linkstat = OMAP_MUSB_VBUS_OFF; | ||
283 | } | ||
281 | 284 | ||
282 | dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", | 285 | dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", |
283 | status, status, linkstat); | 286 | status, status, linkstat); |
284 | 287 | ||
285 | twl->phy.last_event = linkstat; | ||
286 | |||
287 | /* REVISIT this assumes host and peripheral controllers | 288 | /* REVISIT this assumes host and peripheral controllers |
288 | * are registered, and that both are active... | 289 | * are registered, and that both are active... |
289 | */ | 290 | */ |
290 | 291 | ||
291 | spin_lock_irq(&twl->lock); | 292 | spin_lock_irq(&twl->lock); |
292 | twl->linkstat = linkstat; | 293 | twl->linkstat = linkstat; |
293 | if (linkstat == USB_EVENT_ID) { | 294 | if (linkstat == OMAP_MUSB_ID_GROUND) { |
294 | otg->default_a = true; | 295 | otg->default_a = true; |
295 | twl->phy.state = OTG_STATE_A_IDLE; | 296 | twl->phy.state = OTG_STATE_A_IDLE; |
296 | } else { | 297 | } else { |
@@ -501,10 +502,10 @@ static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL); | |||
501 | static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | 502 | static irqreturn_t twl4030_usb_irq(int irq, void *_twl) |
502 | { | 503 | { |
503 | struct twl4030_usb *twl = _twl; | 504 | struct twl4030_usb *twl = _twl; |
504 | int status; | 505 | enum omap_musb_vbus_id_status status; |
505 | 506 | ||
506 | status = twl4030_usb_linkstat(twl); | 507 | status = twl4030_usb_linkstat(twl); |
507 | if (status >= 0) { | 508 | if (status > 0) { |
508 | /* FIXME add a set_power() method so that B-devices can | 509 | /* FIXME add a set_power() method so that B-devices can |
509 | * configure the charger appropriately. It's not always | 510 | * configure the charger appropriately. It's not always |
510 | * correct to consume VBUS power, and how much current to | 511 | * correct to consume VBUS power, and how much current to |
@@ -516,13 +517,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
516 | * USB_LINK_VBUS state. musb_hdrc won't care until it | 517 | * USB_LINK_VBUS state. musb_hdrc won't care until it |
517 | * starts to handle softconnect right. | 518 | * starts to handle softconnect right. |
518 | */ | 519 | */ |
519 | if (status == USB_EVENT_NONE) | 520 | if (status == OMAP_MUSB_VBUS_OFF || |
521 | status == OMAP_MUSB_ID_FLOAT) | ||
520 | twl4030_phy_suspend(twl, 0); | 522 | twl4030_phy_suspend(twl, 0); |
521 | else | 523 | else |
522 | twl4030_phy_resume(twl); | 524 | twl4030_phy_resume(twl); |
523 | 525 | ||
524 | atomic_notifier_call_chain(&twl->phy.notifier, status, | 526 | omap_musb_mailbox(twl->linkstat); |
525 | twl->phy.otg->gadget); | ||
526 | } | 527 | } |
527 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 528 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); |
528 | 529 | ||
@@ -531,11 +532,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
531 | 532 | ||
532 | static void twl4030_usb_phy_init(struct twl4030_usb *twl) | 533 | static void twl4030_usb_phy_init(struct twl4030_usb *twl) |
533 | { | 534 | { |
534 | int status; | 535 | enum omap_musb_vbus_id_status status; |
535 | 536 | ||
536 | status = twl4030_usb_linkstat(twl); | 537 | status = twl4030_usb_linkstat(twl); |
537 | if (status >= 0) { | 538 | if (status > 0) { |
538 | if (status == USB_EVENT_NONE) { | 539 | if (status == OMAP_MUSB_VBUS_OFF || |
540 | status == OMAP_MUSB_ID_FLOAT) { | ||
539 | __twl4030_phy_power(twl, 0); | 541 | __twl4030_phy_power(twl, 0); |
540 | twl->asleep = 1; | 542 | twl->asleep = 1; |
541 | } else { | 543 | } else { |
@@ -543,8 +545,7 @@ static void twl4030_usb_phy_init(struct twl4030_usb *twl) | |||
543 | twl->asleep = 0; | 545 | twl->asleep = 0; |
544 | } | 546 | } |
545 | 547 | ||
546 | atomic_notifier_call_chain(&twl->phy.notifier, status, | 548 | omap_musb_mailbox(twl->linkstat); |
547 | twl->phy.otg->gadget); | ||
548 | } | 549 | } |
549 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 550 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); |
550 | } | 551 | } |
@@ -613,6 +614,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
613 | twl->usb_mode = pdata->usb_mode; | 614 | twl->usb_mode = pdata->usb_mode; |
614 | twl->vbus_supplied = false; | 615 | twl->vbus_supplied = false; |
615 | twl->asleep = 1; | 616 | twl->asleep = 1; |
617 | twl->linkstat = OMAP_MUSB_UNKNOWN; | ||
616 | 618 | ||
617 | twl->phy.dev = twl->dev; | 619 | twl->phy.dev = twl->dev; |
618 | twl->phy.label = "twl4030"; | 620 | twl->phy.label = "twl4030"; |
@@ -639,8 +641,6 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
639 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 641 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
640 | dev_warn(&pdev->dev, "could not create sysfs file\n"); | 642 | dev_warn(&pdev->dev, "could not create sysfs file\n"); |
641 | 643 | ||
642 | ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); | ||
643 | |||
644 | /* Our job is to use irqs and status from the power module | 644 | /* Our job is to use irqs and status from the power module |
645 | * to keep the transceiver disabled when nothing's connected. | 645 | * to keep the transceiver disabled when nothing's connected. |
646 | * | 646 | * |
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index dbee00aea755..6c758836cfb1 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
28 | #include <linux/usb/otg.h> | 28 | #include <linux/usb/otg.h> |
29 | #include <linux/usb/musb-omap.h> | ||
29 | #include <linux/i2c/twl.h> | 30 | #include <linux/i2c/twl.h> |
30 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
31 | #include <linux/err.h> | 32 | #include <linux/err.h> |
32 | #include <linux/notifier.h> | ||
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | 35 | ||
@@ -100,7 +100,7 @@ struct twl6030_usb { | |||
100 | 100 | ||
101 | int irq1; | 101 | int irq1; |
102 | int irq2; | 102 | int irq2; |
103 | u8 linkstat; | 103 | enum omap_musb_vbus_id_status linkstat; |
104 | u8 asleep; | 104 | u8 asleep; |
105 | bool irq_enabled; | 105 | bool irq_enabled; |
106 | bool vbus_enable; | 106 | bool vbus_enable; |
@@ -147,7 +147,7 @@ static int twl6030_phy_init(struct usb_phy *x) | |||
147 | dev = twl->dev; | 147 | dev = twl->dev; |
148 | pdata = dev->platform_data; | 148 | pdata = dev->platform_data; |
149 | 149 | ||
150 | if (twl->linkstat == USB_EVENT_ID) | 150 | if (twl->linkstat == OMAP_MUSB_ID_GROUND) |
151 | pdata->phy_power(twl->dev, 1, 1); | 151 | pdata->phy_power(twl->dev, 1, 1); |
152 | else | 152 | else |
153 | pdata->phy_power(twl->dev, 0, 1); | 153 | pdata->phy_power(twl->dev, 0, 1); |
@@ -235,13 +235,13 @@ static ssize_t twl6030_usb_vbus_show(struct device *dev, | |||
235 | spin_lock_irqsave(&twl->lock, flags); | 235 | spin_lock_irqsave(&twl->lock, flags); |
236 | 236 | ||
237 | switch (twl->linkstat) { | 237 | switch (twl->linkstat) { |
238 | case USB_EVENT_VBUS: | 238 | case OMAP_MUSB_VBUS_VALID: |
239 | ret = snprintf(buf, PAGE_SIZE, "vbus\n"); | 239 | ret = snprintf(buf, PAGE_SIZE, "vbus\n"); |
240 | break; | 240 | break; |
241 | case USB_EVENT_ID: | 241 | case OMAP_MUSB_ID_GROUND: |
242 | ret = snprintf(buf, PAGE_SIZE, "id\n"); | 242 | ret = snprintf(buf, PAGE_SIZE, "id\n"); |
243 | break; | 243 | break; |
244 | case USB_EVENT_NONE: | 244 | case OMAP_MUSB_VBUS_OFF: |
245 | ret = snprintf(buf, PAGE_SIZE, "none\n"); | 245 | ret = snprintf(buf, PAGE_SIZE, "none\n"); |
246 | break; | 246 | break; |
247 | default: | 247 | default: |
@@ -257,7 +257,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) | |||
257 | { | 257 | { |
258 | struct twl6030_usb *twl = _twl; | 258 | struct twl6030_usb *twl = _twl; |
259 | struct usb_otg *otg = twl->phy.otg; | 259 | struct usb_otg *otg = twl->phy.otg; |
260 | int status; | 260 | enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN; |
261 | u8 vbus_state, hw_state; | 261 | u8 vbus_state, hw_state; |
262 | 262 | ||
263 | hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); | 263 | hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); |
@@ -268,22 +268,20 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) | |||
268 | if (vbus_state & VBUS_DET) { | 268 | if (vbus_state & VBUS_DET) { |
269 | regulator_enable(twl->usb3v3); | 269 | regulator_enable(twl->usb3v3); |
270 | twl->asleep = 1; | 270 | twl->asleep = 1; |
271 | status = USB_EVENT_VBUS; | 271 | status = OMAP_MUSB_VBUS_VALID; |
272 | otg->default_a = false; | 272 | otg->default_a = false; |
273 | twl->phy.state = OTG_STATE_B_IDLE; | 273 | twl->phy.state = OTG_STATE_B_IDLE; |
274 | twl->linkstat = status; | 274 | twl->linkstat = status; |
275 | twl->phy.last_event = status; | 275 | omap_musb_mailbox(status); |
276 | atomic_notifier_call_chain(&twl->phy.notifier, | ||
277 | status, otg->gadget); | ||
278 | } else { | 276 | } else { |
279 | status = USB_EVENT_NONE; | 277 | if (twl->linkstat != OMAP_MUSB_UNKNOWN) { |
280 | twl->linkstat = status; | 278 | status = OMAP_MUSB_VBUS_OFF; |
281 | twl->phy.last_event = status; | 279 | twl->linkstat = status; |
282 | atomic_notifier_call_chain(&twl->phy.notifier, | 280 | omap_musb_mailbox(status); |
283 | status, otg->gadget); | 281 | if (twl->asleep) { |
284 | if (twl->asleep) { | 282 | regulator_disable(twl->usb3v3); |
285 | regulator_disable(twl->usb3v3); | 283 | twl->asleep = 0; |
286 | twl->asleep = 0; | 284 | } |
287 | } | 285 | } |
288 | } | 286 | } |
289 | } | 287 | } |
@@ -296,7 +294,7 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) | |||
296 | { | 294 | { |
297 | struct twl6030_usb *twl = _twl; | 295 | struct twl6030_usb *twl = _twl; |
298 | struct usb_otg *otg = twl->phy.otg; | 296 | struct usb_otg *otg = twl->phy.otg; |
299 | int status = USB_EVENT_NONE; | 297 | enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN; |
300 | u8 hw_state; | 298 | u8 hw_state; |
301 | 299 | ||
302 | hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); | 300 | hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); |
@@ -308,13 +306,11 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) | |||
308 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1); | 306 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1); |
309 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, | 307 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, |
310 | 0x10); | 308 | 0x10); |
311 | status = USB_EVENT_ID; | 309 | status = OMAP_MUSB_ID_GROUND; |
312 | otg->default_a = true; | 310 | otg->default_a = true; |
313 | twl->phy.state = OTG_STATE_A_IDLE; | 311 | twl->phy.state = OTG_STATE_A_IDLE; |
314 | twl->linkstat = status; | 312 | twl->linkstat = status; |
315 | twl->phy.last_event = status; | 313 | omap_musb_mailbox(status); |
316 | atomic_notifier_call_chain(&twl->phy.notifier, status, | ||
317 | otg->gadget); | ||
318 | } else { | 314 | } else { |
319 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, | 315 | twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, |
320 | 0x10); | 316 | 0x10); |
@@ -419,6 +415,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) | |||
419 | twl->irq1 = platform_get_irq(pdev, 0); | 415 | twl->irq1 = platform_get_irq(pdev, 0); |
420 | twl->irq2 = platform_get_irq(pdev, 1); | 416 | twl->irq2 = platform_get_irq(pdev, 1); |
421 | twl->features = pdata->features; | 417 | twl->features = pdata->features; |
418 | twl->linkstat = OMAP_MUSB_UNKNOWN; | ||
422 | 419 | ||
423 | twl->phy.dev = twl->dev; | 420 | twl->phy.dev = twl->dev; |
424 | twl->phy.label = "twl6030"; | 421 | twl->phy.label = "twl6030"; |
@@ -449,8 +446,6 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) | |||
449 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 446 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
450 | dev_warn(&pdev->dev, "could not create sysfs file\n"); | 447 | dev_warn(&pdev->dev, "could not create sysfs file\n"); |
451 | 448 | ||
452 | ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); | ||
453 | |||
454 | INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); | 449 | INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); |
455 | 450 | ||
456 | twl->irq_enabled = true; | 451 | twl->irq_enabled = true; |
diff --git a/include/linux/usb/musb-omap.h b/include/linux/usb/musb-omap.h new file mode 100644 index 000000000000..7774c5986f07 --- /dev/null +++ b/include/linux/usb/musb-omap.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011-2012 by Texas Instruments | ||
3 | * | ||
4 | * The Inventra Controller Driver for Linux is free software; you | ||
5 | * can redistribute it and/or modify it under the terms of the GNU | ||
6 | * General Public License version 2 as published by the Free Software | ||
7 | * Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef __MUSB_OMAP_H__ | ||
11 | #define __MUSB_OMAP_H__ | ||
12 | |||
13 | enum omap_musb_vbus_id_status { | ||
14 | OMAP_MUSB_UNKNOWN = 0, | ||
15 | OMAP_MUSB_ID_GROUND, | ||
16 | OMAP_MUSB_ID_FLOAT, | ||
17 | OMAP_MUSB_VBUS_VALID, | ||
18 | OMAP_MUSB_VBUS_OFF, | ||
19 | }; | ||
20 | |||
21 | #if (defined(CONFIG_USB_MUSB_OMAP2PLUS) || \ | ||
22 | defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)) | ||
23 | void omap_musb_mailbox(enum omap_musb_vbus_id_status status); | ||
24 | #else | ||
25 | static inline void omap_musb_mailbox(enum omap_musb_vbus_id_status status) | ||
26 | { | ||
27 | } | ||
28 | #endif | ||
29 | |||
30 | #endif /* __MUSB_OMAP_H__ */ | ||