Hi all,
Some customers here plan to remove TPS2051 to save the cost and require the USB only work in host mode, so how to modify the dts file of the AM335x kernel to support it?
Thanks!
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi all,
Some customers here plan to remove TPS2051 to save the cost and require the USB only work in host mode, so how to modify the dts file of the AM335x kernel to support it?
Thanks!
Yaoming,
Please apply the three patches attached below,
From 064f0cbf226625b752a3364ddbfd34b6be8b5a9b Mon Sep 17 00:00:00 2001 From: Bin Liu <b-liu@ti.com> Date: Mon, 14 Sep 2015 21:07:53 -0500 Subject: [PATCH 1/3] usb: of: add an api to get dr_mode by the phy node Some USB phy drivers have different handling for the controller in each dr_mode. But the phy driver does not have visibility to the dr_mode of the controller. This adds an api to return the dr_mode of the controller which associates the given phy node. Signed-off-by: Bin Liu <b-liu@ti.com> --- drivers/usb/common/common.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/usb/of.h | 6 ++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index b530fd4..e3da800 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -114,6 +114,42 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) EXPORT_SYMBOL_GPL(of_usb_get_dr_mode); /** + * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device + * which is associated with the given phy device_node + * @np: Pointer to the given phy device_node + * + * In dts a usb controller associates with phy devices. The function gets + * the string from property 'dr_mode' of the controller associated with the + * given phy device node, and returns the correspondig enum usb_dr_mode. + */ +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +{ + struct device_node *controller = NULL; + struct device_node *phy; + enum usb_dr_mode dr_mode; + int index; + + do { + controller = of_find_node_with_property(controller, "phys"); + index = 0; + do { + phy = of_parse_phandle(controller, "phys", index); + of_node_put(phy); + if (phy == phy_np) + goto finish; + index++; + } while (phy); + } while (controller); + +finish: + dr_mode = of_usb_get_dr_mode(controller); + of_node_put(controller); + + return dr_mode; +} +EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy); + +/** * of_usb_get_maximum_speed - Get maximum requested speed for a given USB * controller. * @np: Pointer to the given device_node diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index cfe0528..14ebd5a 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -13,6 +13,7 @@ #if IS_ENABLED(CONFIG_OF) enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np); enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np); bool of_usb_host_tpl_support(struct device_node *np); #else @@ -21,6 +22,11 @@ static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) return USB_DR_MODE_UNKNOWN; } +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +{ + return USB_DR_MODE_UNKNOWN; +} + static inline enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np) { -- 1.9.1
From 87dff9895cb9987d7730ef0ac222207bdb1de573 Mon Sep 17 00:00:00 2001 From: Bin Liu <b-liu@ti.com> Date: Mon, 14 Sep 2015 22:47:23 -0500 Subject: [PATCH 2/3] usb: phy: correct the am335x phy header filename The filename of am35x-phy-control.h is confusing. The header is used by the am335x phy driver, but the filename refers to am35x. Even worse there is indeed another device called am35x but it does not use this header at all. Signed-off-by: Bin Liu <b-liu@ti.com> --- drivers/usb/phy/am35x-phy-control.h | 21 --------------------- drivers/usb/phy/phy-am335x-control.c | 2 +- drivers/usb/phy/phy-am335x-control.h | 21 +++++++++++++++++++++ drivers/usb/phy/phy-am335x.c | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) delete mode 100644 drivers/usb/phy/am35x-phy-control.h create mode 100644 drivers/usb/phy/phy-am335x-control.h diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h deleted file mode 100644 index b96594d..0000000 --- a/drivers/usb/phy/am35x-phy-control.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _AM335x_PHY_CONTROL_H_ -#define _AM335x_PHY_CONTROL_H_ - -struct phy_control { - void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); - void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); -}; - -static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on) -{ - phy_ctrl->phy_power(phy_ctrl, id, on); -} - -static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on) -{ - phy_ctrl->phy_wkup(phy_ctrl, id, on); -} - -struct phy_control *am335x_get_phy_control(struct device *dev); - -#endif diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 7b3035f..23fca51 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -4,7 +4,7 @@ #include <linux/of.h> #include <linux/io.h> #include <linux/delay.h> -#include "am35x-phy-control.h" +#include "phy-am335x-control.h" struct am335x_control_usb { struct device *dev; diff --git a/drivers/usb/phy/phy-am335x-control.h b/drivers/usb/phy/phy-am335x-control.h new file mode 100644 index 0000000..b96594d --- /dev/null +++ b/drivers/usb/phy/phy-am335x-control.h @@ -0,0 +1,21 @@ +#ifndef _AM335x_PHY_CONTROL_H_ +#define _AM335x_PHY_CONTROL_H_ + +struct phy_control { + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); +}; + +static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on) +{ + phy_ctrl->phy_power(phy_ctrl, id, on); +} + +static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on) +{ + phy_ctrl->phy_wkup(phy_ctrl, id, on); +} + +struct phy_control *am335x_get_phy_control(struct device *dev); + +#endif diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 90b67a4..8b6139d 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -9,7 +9,7 @@ #include <linux/of.h> #include <linux/of_address.h> -#include "am35x-phy-control.h" +#include "phy-am335x-control.h" #include "phy-generic.h" struct am335x_phy { -- 1.9.1
From 29eac9a2f3f1b36ed3006b9d133aa7acf9aa25af Mon Sep 17 00:00:00 2001 From: Bin Liu <b-liu@ti.com> Date: Mon, 14 Sep 2015 22:22:56 -0500 Subject: [PATCH 3/3] 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> --- drivers/usb/Kconfig | 2 +- drivers/usb/phy/phy-am335x-control.c | 14 +++++++++++--- drivers/usb/phy/phy-am335x-control.h | 8 +++++--- drivers/usb/phy/phy-am335x.c | 15 ++++++++++----- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 5b625e2..b33e00b 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -32,7 +32,7 @@ if USB_SUPPORT config USB_COMMON tristate default y - depends on USB || USB_GADGET || USB_OTG + depends on USB || USB_GADGET || USB_OTG || AM335X_PHY_USB config USB_ARCH_HAS_HCD def_bool y diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 23fca51..42a1afe 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -4,6 +4,7 @@ #include <linux/of.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/usb/otg.h> #include "phy-am335x-control.h" struct am335x_control_usb { @@ -58,7 +59,8 @@ static void am335x_phy_wkup(struct phy_control *phy_ctrl, u32 id, bool on) spin_unlock(&usb_ctrl->lock); } -static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) +static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, + enum usb_dr_mode dr_mode, bool on) { struct am335x_control_usb *usb_ctrl; u32 val; @@ -80,8 +82,14 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) val = readl(usb_ctrl->phy_reg + reg); if (on) { - val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); - val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + if (dr_mode == USB_DR_MODE_HOST) { + val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN | + USBPHY_OTGVDET_EN); + val |= USBPHY_OTGSESSEND_EN; + } else { + val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); + val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + } } else { val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; } diff --git a/drivers/usb/phy/phy-am335x-control.h b/drivers/usb/phy/phy-am335x-control.h index b96594d..e86b316 100644 --- a/drivers/usb/phy/phy-am335x-control.h +++ b/drivers/usb/phy/phy-am335x-control.h @@ -2,13 +2,15 @@ #define _AM335x_PHY_CONTROL_H_ struct phy_control { - void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, + enum usb_dr_mode dr_mode, bool on); void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); }; -static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on) +static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, + enum usb_dr_mode dr_mode, bool on) { - phy_ctrl->phy_power(phy_ctrl, id, on); + phy_ctrl->phy_power(phy_ctrl, id, dr_mode, on); } 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 8b6139d..39b424f 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -8,6 +8,7 @@ #include <linux/regulator/consumer.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/usb/of.h> #include "phy-am335x-control.h" #include "phy-generic.h" @@ -16,13 +17,14 @@ struct am335x_phy { struct usb_phy_generic usb_phy_gen; struct phy_control *phy_ctrl; int id; + enum usb_dr_mode dr_mode; }; static int am335x_init(struct usb_phy *phy) { struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); - phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true); return 0; } @@ -30,7 +32,7 @@ static void am335x_shutdown(struct usb_phy *phy) { struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); - phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); } static int am335x_phy_probe(struct platform_device *pdev) @@ -46,12 +48,15 @@ static int am335x_phy_probe(struct platform_device *pdev) am_phy->phy_ctrl = am335x_get_phy_control(dev); if (!am_phy->phy_ctrl) return -EPROBE_DEFER; + am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy"); if (am_phy->id < 0) { dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id); return am_phy->id; } + am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node); + ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL); if (ret) return ret; @@ -75,7 +80,7 @@ static int am335x_phy_probe(struct platform_device *pdev) */ device_set_wakeup_enable(dev, false); - phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); return 0; } @@ -105,7 +110,7 @@ static int am335x_phy_suspend(struct device *dev) if (device_may_wakeup(dev)) phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true); - phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); return 0; } @@ -115,7 +120,7 @@ static int am335x_phy_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct am335x_phy *am_phy = platform_get_drvdata(pdev); - phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true); if (device_may_wakeup(dev)) phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false); -- 1.9.1
and follow the wiki http://processors.wiki.ti.com/index.php/MUSB_Linux_Porting_Guide to set the proper dr_mode for the USB port in host-only mode. Nothing else in kernel needs to be changed.
This is tested with Processor SDK2.0 kernel.