diff options
Diffstat (limited to 'drivers/usb/musb/sunxi.c')
| -rw-r--r-- | drivers/usb/musb/sunxi.c | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index fdab4232cfbf..76500515dd8b 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c | |||
| @@ -80,7 +80,8 @@ static struct musb *sunxi_musb; | |||
| 80 | 80 | ||
| 81 | struct sunxi_glue { | 81 | struct sunxi_glue { |
| 82 | struct device *dev; | 82 | struct device *dev; |
| 83 | struct platform_device *musb; | 83 | struct musb *musb; |
| 84 | struct platform_device *musb_pdev; | ||
| 84 | struct clk *clk; | 85 | struct clk *clk; |
| 85 | struct reset_control *rst; | 86 | struct reset_control *rst; |
| 86 | struct phy *phy; | 87 | struct phy *phy; |
| @@ -102,7 +103,7 @@ static void sunxi_musb_work(struct work_struct *work) | |||
| 102 | return; | 103 | return; |
| 103 | 104 | ||
| 104 | if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { | 105 | if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { |
| 105 | struct musb *musb = platform_get_drvdata(glue->musb); | 106 | struct musb *musb = glue->musb; |
| 106 | unsigned long flags; | 107 | unsigned long flags; |
| 107 | u8 devctl; | 108 | u8 devctl; |
| 108 | 109 | ||
| @@ -112,7 +113,7 @@ static void sunxi_musb_work(struct work_struct *work) | |||
| 112 | if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { | 113 | if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { |
| 113 | set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); | 114 | set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); |
| 114 | musb->xceiv->otg->default_a = 1; | 115 | musb->xceiv->otg->default_a = 1; |
| 115 | musb->xceiv->otg->state = OTG_STATE_A_IDLE; | 116 | musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; |
| 116 | MUSB_HST_MODE(musb); | 117 | MUSB_HST_MODE(musb); |
| 117 | devctl |= MUSB_DEVCTL_SESSION; | 118 | devctl |= MUSB_DEVCTL_SESSION; |
| 118 | } else { | 119 | } else { |
| @@ -145,10 +146,12 @@ static void sunxi_musb_set_vbus(struct musb *musb, int is_on) | |||
| 145 | { | 146 | { |
| 146 | struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); | 147 | struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); |
| 147 | 148 | ||
| 148 | if (is_on) | 149 | if (is_on) { |
| 149 | set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); | 150 | set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); |
| 150 | else | 151 | musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; |
| 152 | } else { | ||
| 151 | clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); | 153 | clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); |
| 154 | } | ||
| 152 | 155 | ||
| 153 | schedule_work(&glue->work); | 156 | schedule_work(&glue->work); |
| 154 | } | 157 | } |
| @@ -264,15 +267,6 @@ static int sunxi_musb_init(struct musb *musb) | |||
| 264 | if (ret) | 267 | if (ret) |
| 265 | goto error_unregister_notifier; | 268 | goto error_unregister_notifier; |
| 266 | 269 | ||
| 267 | if (musb->port_mode == MUSB_PORT_MODE_HOST) { | ||
| 268 | ret = phy_power_on(glue->phy); | ||
| 269 | if (ret) | ||
| 270 | goto error_phy_exit; | ||
| 271 | set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); | ||
| 272 | /* Stop musb work from turning vbus off again */ | ||
| 273 | set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); | ||
| 274 | } | ||
| 275 | |||
| 276 | musb->isr = sunxi_musb_interrupt; | 270 | musb->isr = sunxi_musb_interrupt; |
| 277 | 271 | ||
| 278 | /* Stop the musb-core from doing runtime pm (not supported on sunxi) */ | 272 | /* Stop the musb-core from doing runtime pm (not supported on sunxi) */ |
| @@ -280,8 +274,6 @@ static int sunxi_musb_init(struct musb *musb) | |||
| 280 | 274 | ||
| 281 | return 0; | 275 | return 0; |
| 282 | 276 | ||
| 283 | error_phy_exit: | ||
| 284 | phy_exit(glue->phy); | ||
| 285 | error_unregister_notifier: | 277 | error_unregister_notifier: |
| 286 | if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) | 278 | if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) |
| 287 | extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, | 279 | extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, |
| @@ -323,10 +315,31 @@ static int sunxi_musb_exit(struct musb *musb) | |||
| 323 | return 0; | 315 | return 0; |
| 324 | } | 316 | } |
| 325 | 317 | ||
| 318 | static int sunxi_set_mode(struct musb *musb, u8 mode) | ||
| 319 | { | ||
| 320 | struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); | ||
| 321 | int ret; | ||
| 322 | |||
| 323 | if (mode == MUSB_HOST) { | ||
| 324 | ret = phy_power_on(glue->phy); | ||
| 325 | if (ret) | ||
| 326 | return ret; | ||
| 327 | |||
| 328 | set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); | ||
| 329 | /* Stop musb work from turning vbus off again */ | ||
| 330 | set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); | ||
| 331 | musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; | ||
| 332 | } | ||
| 333 | |||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 326 | static void sunxi_musb_enable(struct musb *musb) | 337 | static void sunxi_musb_enable(struct musb *musb) |
| 327 | { | 338 | { |
| 328 | struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); | 339 | struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); |
| 329 | 340 | ||
| 341 | glue->musb = musb; | ||
| 342 | |||
| 330 | /* musb_core does not call us in a balanced manner */ | 343 | /* musb_core does not call us in a balanced manner */ |
| 331 | if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) | 344 | if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) |
| 332 | return; | 345 | return; |
| @@ -569,6 +582,7 @@ static const struct musb_platform_ops sunxi_musb_ops = { | |||
| 569 | .exit = sunxi_musb_exit, | 582 | .exit = sunxi_musb_exit, |
| 570 | .enable = sunxi_musb_enable, | 583 | .enable = sunxi_musb_enable, |
| 571 | .disable = sunxi_musb_disable, | 584 | .disable = sunxi_musb_disable, |
| 585 | .set_mode = sunxi_set_mode, | ||
| 572 | .fifo_offset = sunxi_musb_fifo_offset, | 586 | .fifo_offset = sunxi_musb_fifo_offset, |
| 573 | .ep_offset = sunxi_musb_ep_offset, | 587 | .ep_offset = sunxi_musb_ep_offset, |
| 574 | .busctl_offset = sunxi_musb_busctl_offset, | 588 | .busctl_offset = sunxi_musb_busctl_offset, |
| @@ -721,9 +735,9 @@ static int sunxi_musb_probe(struct platform_device *pdev) | |||
| 721 | pinfo.data = &pdata; | 735 | pinfo.data = &pdata; |
| 722 | pinfo.size_data = sizeof(pdata); | 736 | pinfo.size_data = sizeof(pdata); |
| 723 | 737 | ||
| 724 | glue->musb = platform_device_register_full(&pinfo); | 738 | glue->musb_pdev = platform_device_register_full(&pinfo); |
| 725 | if (IS_ERR(glue->musb)) { | 739 | if (IS_ERR(glue->musb_pdev)) { |
| 726 | ret = PTR_ERR(glue->musb); | 740 | ret = PTR_ERR(glue->musb_pdev); |
| 727 | dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); | 741 | dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); |
| 728 | goto err_unregister_usb_phy; | 742 | goto err_unregister_usb_phy; |
| 729 | } | 743 | } |
| @@ -740,7 +754,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) | |||
| 740 | struct sunxi_glue *glue = platform_get_drvdata(pdev); | 754 | struct sunxi_glue *glue = platform_get_drvdata(pdev); |
| 741 | struct platform_device *usb_phy = glue->usb_phy; | 755 | struct platform_device *usb_phy = glue->usb_phy; |
| 742 | 756 | ||
| 743 | platform_device_unregister(glue->musb); /* Frees glue ! */ | 757 | platform_device_unregister(glue->musb_pdev); |
| 744 | usb_phy_generic_unregister(usb_phy); | 758 | usb_phy_generic_unregister(usb_phy); |
| 745 | 759 | ||
| 746 | return 0; | 760 | return 0; |
