diff options
Diffstat (limited to 'drivers/usb/otg/twl4030-usb.c')
-rw-r--r-- | drivers/usb/otg/twl4030-usb.c | 73 |
1 files changed, 28 insertions, 45 deletions
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index c4a86da858e2..523cad5bfea9 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,11 +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 | 254 | ||
255 | twl->vbus_supplied = false; | 255 | twl->vbus_supplied = false; |
256 | 256 | ||
@@ -273,30 +273,23 @@ static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl) | |||
273 | twl->vbus_supplied = true; | 273 | twl->vbus_supplied = true; |
274 | 274 | ||
275 | if (status & BIT(2)) | 275 | if (status & BIT(2)) |
276 | linkstat = USB_EVENT_ID; | 276 | linkstat = OMAP_MUSB_ID_GROUND; |
277 | else | 277 | else |
278 | linkstat = USB_EVENT_VBUS; | 278 | linkstat = OMAP_MUSB_VBUS_VALID; |
279 | } else | 279 | } else { |
280 | linkstat = USB_EVENT_NONE; | 280 | if (twl->linkstat != OMAP_MUSB_UNKNOWN) |
281 | linkstat = OMAP_MUSB_VBUS_OFF; | ||
282 | } | ||
281 | 283 | ||
282 | dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", | 284 | dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", |
283 | status, status, linkstat); | 285 | status, status, linkstat); |
284 | 286 | ||
285 | twl->phy.last_event = linkstat; | ||
286 | |||
287 | /* REVISIT this assumes host and peripheral controllers | 287 | /* REVISIT this assumes host and peripheral controllers |
288 | * are registered, and that both are active... | 288 | * are registered, and that both are active... |
289 | */ | 289 | */ |
290 | 290 | ||
291 | spin_lock_irq(&twl->lock); | 291 | spin_lock_irq(&twl->lock); |
292 | twl->linkstat = linkstat; | 292 | twl->linkstat = linkstat; |
293 | if (linkstat == USB_EVENT_ID) { | ||
294 | otg->default_a = true; | ||
295 | twl->phy.state = OTG_STATE_A_IDLE; | ||
296 | } else { | ||
297 | otg->default_a = false; | ||
298 | twl->phy.state = OTG_STATE_B_IDLE; | ||
299 | } | ||
300 | spin_unlock_irq(&twl->lock); | 293 | spin_unlock_irq(&twl->lock); |
301 | 294 | ||
302 | return linkstat; | 295 | return linkstat; |
@@ -501,10 +494,10 @@ static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL); | |||
501 | static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | 494 | static irqreturn_t twl4030_usb_irq(int irq, void *_twl) |
502 | { | 495 | { |
503 | struct twl4030_usb *twl = _twl; | 496 | struct twl4030_usb *twl = _twl; |
504 | int status; | 497 | enum omap_musb_vbus_id_status status; |
505 | 498 | ||
506 | status = twl4030_usb_linkstat(twl); | 499 | status = twl4030_usb_linkstat(twl); |
507 | if (status >= 0) { | 500 | if (status > 0) { |
508 | /* FIXME add a set_power() method so that B-devices can | 501 | /* FIXME add a set_power() method so that B-devices can |
509 | * configure the charger appropriately. It's not always | 502 | * configure the charger appropriately. It's not always |
510 | * correct to consume VBUS power, and how much current to | 503 | * correct to consume VBUS power, and how much current to |
@@ -516,13 +509,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
516 | * USB_LINK_VBUS state. musb_hdrc won't care until it | 509 | * USB_LINK_VBUS state. musb_hdrc won't care until it |
517 | * starts to handle softconnect right. | 510 | * starts to handle softconnect right. |
518 | */ | 511 | */ |
519 | if (status == USB_EVENT_NONE) | 512 | if (status == OMAP_MUSB_VBUS_OFF || |
513 | status == OMAP_MUSB_ID_FLOAT) | ||
520 | twl4030_phy_suspend(twl, 0); | 514 | twl4030_phy_suspend(twl, 0); |
521 | else | 515 | else |
522 | twl4030_phy_resume(twl); | 516 | twl4030_phy_resume(twl); |
523 | 517 | ||
524 | atomic_notifier_call_chain(&twl->phy.notifier, status, | 518 | omap_musb_mailbox(twl->linkstat); |
525 | twl->phy.otg->gadget); | ||
526 | } | 519 | } |
527 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 520 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); |
528 | 521 | ||
@@ -531,11 +524,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
531 | 524 | ||
532 | static void twl4030_usb_phy_init(struct twl4030_usb *twl) | 525 | static void twl4030_usb_phy_init(struct twl4030_usb *twl) |
533 | { | 526 | { |
534 | int status; | 527 | enum omap_musb_vbus_id_status status; |
535 | 528 | ||
536 | status = twl4030_usb_linkstat(twl); | 529 | status = twl4030_usb_linkstat(twl); |
537 | if (status >= 0) { | 530 | if (status > 0) { |
538 | if (status == USB_EVENT_NONE) { | 531 | if (status == OMAP_MUSB_VBUS_OFF || |
532 | status == OMAP_MUSB_ID_FLOAT) { | ||
539 | __twl4030_phy_power(twl, 0); | 533 | __twl4030_phy_power(twl, 0); |
540 | twl->asleep = 1; | 534 | twl->asleep = 1; |
541 | } else { | 535 | } else { |
@@ -543,8 +537,7 @@ static void twl4030_usb_phy_init(struct twl4030_usb *twl) | |||
543 | twl->asleep = 0; | 537 | twl->asleep = 0; |
544 | } | 538 | } |
545 | 539 | ||
546 | atomic_notifier_call_chain(&twl->phy.notifier, status, | 540 | omap_musb_mailbox(twl->linkstat); |
547 | twl->phy.otg->gadget); | ||
548 | } | 541 | } |
549 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 542 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); |
550 | } | 543 | } |
@@ -598,21 +591,20 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
598 | return -EINVAL; | 591 | return -EINVAL; |
599 | } | 592 | } |
600 | 593 | ||
601 | twl = kzalloc(sizeof *twl, GFP_KERNEL); | 594 | twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL); |
602 | if (!twl) | 595 | if (!twl) |
603 | return -ENOMEM; | 596 | return -ENOMEM; |
604 | 597 | ||
605 | otg = kzalloc(sizeof *otg, GFP_KERNEL); | 598 | otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL); |
606 | if (!otg) { | 599 | if (!otg) |
607 | kfree(twl); | ||
608 | return -ENOMEM; | 600 | return -ENOMEM; |
609 | } | ||
610 | 601 | ||
611 | twl->dev = &pdev->dev; | 602 | twl->dev = &pdev->dev; |
612 | twl->irq = platform_get_irq(pdev, 0); | 603 | twl->irq = platform_get_irq(pdev, 0); |
613 | twl->usb_mode = pdata->usb_mode; | 604 | twl->usb_mode = pdata->usb_mode; |
614 | twl->vbus_supplied = false; | 605 | twl->vbus_supplied = false; |
615 | twl->asleep = 1; | 606 | twl->asleep = 1; |
607 | twl->linkstat = OMAP_MUSB_UNKNOWN; | ||
616 | 608 | ||
617 | twl->phy.dev = twl->dev; | 609 | twl->phy.dev = twl->dev; |
618 | twl->phy.label = "twl4030"; | 610 | twl->phy.label = "twl4030"; |
@@ -629,18 +621,14 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
629 | err = twl4030_usb_ldo_init(twl); | 621 | err = twl4030_usb_ldo_init(twl); |
630 | if (err) { | 622 | if (err) { |
631 | dev_err(&pdev->dev, "ldo init failed\n"); | 623 | dev_err(&pdev->dev, "ldo init failed\n"); |
632 | kfree(otg); | ||
633 | kfree(twl); | ||
634 | return err; | 624 | return err; |
635 | } | 625 | } |
636 | usb_set_transceiver(&twl->phy); | 626 | usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2); |
637 | 627 | ||
638 | platform_set_drvdata(pdev, twl); | 628 | platform_set_drvdata(pdev, twl); |
639 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 629 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
640 | dev_warn(&pdev->dev, "could not create sysfs file\n"); | 630 | dev_warn(&pdev->dev, "could not create sysfs file\n"); |
641 | 631 | ||
642 | ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); | ||
643 | |||
644 | /* Our job is to use irqs and status from the power module | 632 | /* Our job is to use irqs and status from the power module |
645 | * to keep the transceiver disabled when nothing's connected. | 633 | * to keep the transceiver disabled when nothing's connected. |
646 | * | 634 | * |
@@ -651,13 +639,11 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
651 | */ | 639 | */ |
652 | twl->irq_enabled = true; | 640 | twl->irq_enabled = true; |
653 | status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq, | 641 | status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq, |
654 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 642 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | |
655 | "twl4030_usb", twl); | 643 | IRQF_ONESHOT, "twl4030_usb", twl); |
656 | if (status < 0) { | 644 | if (status < 0) { |
657 | dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n", | 645 | dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n", |
658 | twl->irq, status); | 646 | twl->irq, status); |
659 | kfree(otg); | ||
660 | kfree(twl); | ||
661 | return status; | 647 | return status; |
662 | } | 648 | } |
663 | 649 | ||
@@ -701,9 +687,6 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev) | |||
701 | regulator_put(twl->usb1v8); | 687 | regulator_put(twl->usb1v8); |
702 | regulator_put(twl->usb3v1); | 688 | regulator_put(twl->usb3v1); |
703 | 689 | ||
704 | kfree(twl->phy.otg); | ||
705 | kfree(twl); | ||
706 | |||
707 | return 0; | 690 | return 0; |
708 | } | 691 | } |
709 | 692 | ||