diff options
| author | Bin Liu <b-liu@ti.com> | 2015-12-08 11:31:50 -0500 |
|---|---|---|
| committer | Felipe Balbi <balbi@ti.com> | 2015-12-16 11:07:25 -0500 |
| commit | 59f042f644c5aa10b65b7881966bed78c5c82923 (patch) | |
| tree | 6e5be33e51cc8035ce08302e84b74ed0c03cc29f /drivers/usb/phy | |
| parent | 5306661eff1a70f99456340eddf8e0cf85c2e8af (diff) | |
usb: phy: phy-am335x: bypass first VBUS sensing for host-only mode
To prevent VBUS contention, the am335x MUSB phy senses VBUS first before
transitioning to host mode. However, for host-only mode, VBUS could be
directly tied to 5V power rail which could prevent MUSB transitions to
host mode.
This change receives dr_mode of the controller then bypass the first
VBUS sensing for host-only mode, so that MUSB can work in host mode
event if VBUS is tied to 5V.
Signed-off-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy')
| -rw-r--r-- | drivers/usb/phy/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/usb/phy/phy-am335x-control.c | 14 | ||||
| -rw-r--r-- | drivers/usb/phy/phy-am335x-control.h | 8 | ||||
| -rw-r--r-- | drivers/usb/phy/phy-am335x.c | 15 |
4 files changed, 27 insertions, 11 deletions
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 155694c1a536..c6904742e2aa 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig | |||
| @@ -66,6 +66,7 @@ config AM335X_PHY_USB | |||
| 66 | select USB_PHY | 66 | select USB_PHY |
| 67 | select AM335X_CONTROL_USB | 67 | select AM335X_CONTROL_USB |
| 68 | select NOP_USB_XCEIV | 68 | select NOP_USB_XCEIV |
| 69 | select USB_COMMON | ||
| 69 | help | 70 | help |
| 70 | This driver provides PHY support for that phy which part for the | 71 | This driver provides PHY support for that phy which part for the |
| 71 | AM335x SoC. | 72 | AM335x SoC. |
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 23fca5192a6b..42a1afe36a90 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <linux/of.h> | 4 | #include <linux/of.h> |
| 5 | #include <linux/io.h> | 5 | #include <linux/io.h> |
| 6 | #include <linux/delay.h> | 6 | #include <linux/delay.h> |
| 7 | #include <linux/usb/otg.h> | ||
| 7 | #include "phy-am335x-control.h" | 8 | #include "phy-am335x-control.h" |
| 8 | 9 | ||
| 9 | struct am335x_control_usb { | 10 | struct am335x_control_usb { |
| @@ -58,7 +59,8 @@ static void am335x_phy_wkup(struct phy_control *phy_ctrl, u32 id, bool on) | |||
| 58 | spin_unlock(&usb_ctrl->lock); | 59 | spin_unlock(&usb_ctrl->lock); |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) | 62 | static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, |
| 63 | enum usb_dr_mode dr_mode, bool on) | ||
| 62 | { | 64 | { |
| 63 | struct am335x_control_usb *usb_ctrl; | 65 | struct am335x_control_usb *usb_ctrl; |
| 64 | u32 val; | 66 | u32 val; |
| @@ -80,8 +82,14 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) | |||
| 80 | 82 | ||
| 81 | val = readl(usb_ctrl->phy_reg + reg); | 83 | val = readl(usb_ctrl->phy_reg + reg); |
| 82 | if (on) { | 84 | if (on) { |
| 83 | val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); | 85 | if (dr_mode == USB_DR_MODE_HOST) { |
| 84 | val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; | 86 | val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN | |
| 87 | USBPHY_OTGVDET_EN); | ||
| 88 | val |= USBPHY_OTGSESSEND_EN; | ||
| 89 | } else { | ||
| 90 | val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); | ||
| 91 | val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; | ||
| 92 | } | ||
| 85 | } else { | 93 | } else { |
| 86 | val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; | 94 | val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; |
| 87 | } | 95 | } |
diff --git a/drivers/usb/phy/phy-am335x-control.h b/drivers/usb/phy/phy-am335x-control.h index b96594d1962c..e86b3165d69d 100644 --- a/drivers/usb/phy/phy-am335x-control.h +++ b/drivers/usb/phy/phy-am335x-control.h | |||
| @@ -2,13 +2,15 @@ | |||
| 2 | #define _AM335x_PHY_CONTROL_H_ | 2 | #define _AM335x_PHY_CONTROL_H_ |
| 3 | 3 | ||
| 4 | struct phy_control { | 4 | struct phy_control { |
| 5 | void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); | 5 | void (*phy_power)(struct phy_control *phy_ctrl, u32 id, |
| 6 | enum usb_dr_mode dr_mode, bool on); | ||
| 6 | void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); | 7 | void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); |
| 7 | }; | 8 | }; |
| 8 | 9 | ||
| 9 | static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on) | 10 | static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, |
| 11 | enum usb_dr_mode dr_mode, bool on) | ||
| 10 | { | 12 | { |
| 11 | phy_ctrl->phy_power(phy_ctrl, id, on); | 13 | phy_ctrl->phy_power(phy_ctrl, id, dr_mode, on); |
| 12 | } | 14 | } |
| 13 | 15 | ||
| 14 | static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on) | 16 | static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on) |
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 8b6139dec5eb..39b424f7f629 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/regulator/consumer.h> | 8 | #include <linux/regulator/consumer.h> |
| 9 | #include <linux/of.h> | 9 | #include <linux/of.h> |
| 10 | #include <linux/of_address.h> | 10 | #include <linux/of_address.h> |
| 11 | #include <linux/usb/of.h> | ||
| 11 | 12 | ||
| 12 | #include "phy-am335x-control.h" | 13 | #include "phy-am335x-control.h" |
| 13 | #include "phy-generic.h" | 14 | #include "phy-generic.h" |
| @@ -16,13 +17,14 @@ struct am335x_phy { | |||
| 16 | struct usb_phy_generic usb_phy_gen; | 17 | struct usb_phy_generic usb_phy_gen; |
| 17 | struct phy_control *phy_ctrl; | 18 | struct phy_control *phy_ctrl; |
| 18 | int id; | 19 | int id; |
| 20 | enum usb_dr_mode dr_mode; | ||
| 19 | }; | 21 | }; |
| 20 | 22 | ||
| 21 | static int am335x_init(struct usb_phy *phy) | 23 | static int am335x_init(struct usb_phy *phy) |
| 22 | { | 24 | { |
| 23 | struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); | 25 | struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); |
| 24 | 26 | ||
| 25 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); | 27 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true); |
| 26 | return 0; | 28 | return 0; |
| 27 | } | 29 | } |
| 28 | 30 | ||
| @@ -30,7 +32,7 @@ static void am335x_shutdown(struct usb_phy *phy) | |||
| 30 | { | 32 | { |
| 31 | struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); | 33 | struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); |
| 32 | 34 | ||
| 33 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); | 35 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); |
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | static int am335x_phy_probe(struct platform_device *pdev) | 38 | static int am335x_phy_probe(struct platform_device *pdev) |
| @@ -46,12 +48,15 @@ static int am335x_phy_probe(struct platform_device *pdev) | |||
| 46 | am_phy->phy_ctrl = am335x_get_phy_control(dev); | 48 | am_phy->phy_ctrl = am335x_get_phy_control(dev); |
| 47 | if (!am_phy->phy_ctrl) | 49 | if (!am_phy->phy_ctrl) |
| 48 | return -EPROBE_DEFER; | 50 | return -EPROBE_DEFER; |
| 51 | |||
| 49 | am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy"); | 52 | am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy"); |
| 50 | if (am_phy->id < 0) { | 53 | if (am_phy->id < 0) { |
| 51 | dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id); | 54 | dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id); |
| 52 | return am_phy->id; | 55 | return am_phy->id; |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 58 | am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node); | ||
| 59 | |||
| 55 | ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL); | 60 | ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL); |
| 56 | if (ret) | 61 | if (ret) |
| 57 | return ret; | 62 | return ret; |
| @@ -75,7 +80,7 @@ static int am335x_phy_probe(struct platform_device *pdev) | |||
| 75 | */ | 80 | */ |
| 76 | 81 | ||
| 77 | device_set_wakeup_enable(dev, false); | 82 | device_set_wakeup_enable(dev, false); |
| 78 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); | 83 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); |
| 79 | 84 | ||
| 80 | return 0; | 85 | return 0; |
| 81 | } | 86 | } |
| @@ -105,7 +110,7 @@ static int am335x_phy_suspend(struct device *dev) | |||
| 105 | if (device_may_wakeup(dev)) | 110 | if (device_may_wakeup(dev)) |
| 106 | phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true); | 111 | phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true); |
| 107 | 112 | ||
| 108 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); | 113 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); |
| 109 | 114 | ||
| 110 | return 0; | 115 | return 0; |
| 111 | } | 116 | } |
| @@ -115,7 +120,7 @@ static int am335x_phy_resume(struct device *dev) | |||
| 115 | struct platform_device *pdev = to_platform_device(dev); | 120 | struct platform_device *pdev = to_platform_device(dev); |
| 116 | struct am335x_phy *am_phy = platform_get_drvdata(pdev); | 121 | struct am335x_phy *am_phy = platform_get_drvdata(pdev); |
| 117 | 122 | ||
| 118 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); | 123 | phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true); |
| 119 | 124 | ||
| 120 | if (device_may_wakeup(dev)) | 125 | if (device_may_wakeup(dev)) |
| 121 | phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false); | 126 | phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false); |
