Message ID | 1373416455-30358-1-git-send-email-jwerner@chromium.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Jul 09, 2013 at 05:34:15PM -0700, Julius Werner wrote: > This patch adds support for a new 'samsung,hsic-reset-gpio' in the > device tree, which will be interpreted as an active-low reset pin during > PHY initialization when it exists. Useful for intergrated HSIC devices > like an SMSC 3503 hub. It is necessary to add this directly to the PHY > initialization to get the timing right, since resetting a HSIC device > after it has already been enumerated can confuse the USB stack. > > Also fixes PHY semaphore code to make sure we always go through the > setup at least once, even if it was already turned on (e.g. by > firmware), and changes a spinlock to a mutex to allow sleeping in the > critical section. > > Change-Id: Ieecac52c27daa7a17a7ed3b2863ddba3aeb8d16f > Signed-off-by: Julius Werner <jwerner@chromium.org> > --- > .../devicetree/bindings/usb/samsung-usbphy.txt | 10 ++++++ > drivers/usb/phy/phy-samsung-usb.c | 17 ++++++++++ > drivers/usb/phy/phy-samsung-usb.h | 7 ++-- > drivers/usb/phy/phy-samsung-usb2.c | 38 ++++++++++------------ > drivers/usb/phy/phy-samsung-usb3.c | 12 +++---- > 5 files changed, 55 insertions(+), 29 deletions(-) > > diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > index 33fd354..82e2e16 100644 > --- a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > +++ b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > @@ -31,6 +31,12 @@ Optional properties: > - ranges: allows valid translation between child's address space and parent's > address space. > > +- samsung,hsic-reset-gpio: an active low GPIO pin that resets a device > + connected to the HSIC port. Useful for things like > + an on-board SMSC3503 hub. > +- pinctrl-0: Pin control group containing the HSIC reset GPIO pin. > +- pinctrl-names: Should contain only one value - "default". > + > - The child node 'usbphy-sys' to the node 'usbphy' is for the system controller > interface for usb-phy. It should provide the following information required by > usb-phy controller to control phy. > @@ -56,6 +62,10 @@ Example: > clocks = <&clock 2>, <&clock 305>; > clock-names = "xusbxti", "otg"; > > + samsung,hsic-reset-gpio = <&gpx2 4 1>; looks like this should be modeled as a fixed-regulator ?
Hi Felipe, This is intended to pull down a reset signal line, not to switch power to the device. I could implement that with the regulator framework too, but I think that would just be confusing and harder to understand without providing any benefit. It's really just a plain old GPIO. -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wednesday, July 10, 2013 9:34 AM, Julius Werner wrote: > > This patch adds support for a new 'samsung,hsic-reset-gpio' in the > device tree, which will be interpreted as an active-low reset pin during > PHY initialization when it exists. Useful for intergrated HSIC devices > like an SMSC 3503 hub. It is necessary to add this directly to the PHY > initialization to get the timing right, since resetting a HSIC device > after it has already been enumerated can confuse the USB stack. > > Also fixes PHY semaphore code to make sure we always go through the > setup at least once, even if it was already turned on (e.g. by > firmware), and changes a spinlock to a mutex to allow sleeping in the > critical section. CC'ed Thomas Abraham, This reset signal pin seems 'HUB_RESET' pin to reset SMSC 3503 hub on Arndale board. This reset pin is described that 'This active low signal is used by the system to reset the chip' in SMSC 3503 hub datasheet. One more thing, 'phy-samsung-usb*.c' files are used and designed to control USB PHY controller in Exynos SoCs; thus, these files should control only internal USB PHY controller in Exynos SoCs. However, the reset pin is used for reset external SMSC 3503 hub chip that is not placed in Exynos SoC. Thus, there should not be HUB reset code in ./drivers/usb/phy/phy-samsung-usb*.c This topic was already discussed one month ago. As Olof Johansson mentioned, 'drivers/platform/arm/' would be a good alternative; thus, USB hub reset code should be moved to 'drivers/platform/arm/'. Please refer to the discussion. (http://patches.linaro.org/16856/) Best regards, Jingoo Han > > Change-Id: Ieecac52c27daa7a17a7ed3b2863ddba3aeb8d16f > Signed-off-by: Julius Werner <jwerner@chromium.org> > --- > .../devicetree/bindings/usb/samsung-usbphy.txt | 10 ++++++ > drivers/usb/phy/phy-samsung-usb.c | 17 ++++++++++ > drivers/usb/phy/phy-samsung-usb.h | 7 ++-- > drivers/usb/phy/phy-samsung-usb2.c | 38 ++++++++++------------ > drivers/usb/phy/phy-samsung-usb3.c | 12 +++---- > 5 files changed, 55 insertions(+), 29 deletions(-) > > diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > index 33fd354..82e2e16 100644 > --- a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > +++ b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt > @@ -31,6 +31,12 @@ Optional properties: > - ranges: allows valid translation between child's address space and parent's > address space. > > +- samsung,hsic-reset-gpio: an active low GPIO pin that resets a device > + connected to the HSIC port. Useful for things like > + an on-board SMSC3503 hub. > +- pinctrl-0: Pin control group containing the HSIC reset GPIO pin. > +- pinctrl-names: Should contain only one value - "default". > + > - The child node 'usbphy-sys' to the node 'usbphy' is for the system controller > interface for usb-phy. It should provide the following information required by > usb-phy controller to control phy. > @@ -56,6 +62,10 @@ Example: > clocks = <&clock 2>, <&clock 305>; > clock-names = "xusbxti", "otg"; > > + samsung,hsic-reset-gpio = <&gpx2 4 1>; > + pinctrl-names = "default"; > + pinctrl-0 = <&hsic_reset>; > + > usbphy-sys { > /* USB device and host PHY_CONTROL registers */ > reg = <0x10020704 0x8>; > diff --git a/drivers/usb/phy/phy-samsung-usb.c b/drivers/usb/phy/phy-samsung-usb.c > index ac025ca..23f1d70 100644 > --- a/drivers/usb/phy/phy-samsung-usb.c > +++ b/drivers/usb/phy/phy-samsung-usb.c > @@ -27,6 +27,7 @@ > #include <linux/io.h> > #include <linux/of.h> > #include <linux/of_address.h> > +#include <linux/of_gpio.h> > #include <linux/usb/samsung_usb_phy.h> > > #include "phy-samsung-usb.h" > @@ -58,6 +59,22 @@ int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy) > if (sphy->sysreg == NULL) > dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n"); > > + /* > + * Some boards have a separate active-low reset GPIO for their HSIC USB > + * devices. If they don't, this will just stay at an invalid value and > + * the init code will ignore it. > + */ > + sphy->hsic_reset_gpio = of_get_named_gpio(sphy->dev->of_node, > + "samsung,hsic-reset-gpio", 0); > + if (gpio_is_valid(sphy->hsic_reset_gpio)) { > + if (devm_gpio_request_one(sphy->dev, sphy->hsic_reset_gpio, > + GPIOF_OUT_INIT_LOW, "samsung_hsic_reset")) { > + dev_err(sphy->dev, "can't request hsic reset gpio %d\n", > + sphy->hsic_reset_gpio); > + sphy->hsic_reset_gpio = -EINVAL; > + } > + } > + > of_node_put(usbphy_sys); > > return 0; > diff --git a/drivers/usb/phy/phy-samsung-usb.h b/drivers/usb/phy/phy-samsung-usb.h > index 68771bf..0703878 100644 > --- a/drivers/usb/phy/phy-samsung-usb.h > +++ b/drivers/usb/phy/phy-samsung-usb.h > @@ -16,6 +16,7 @@ > * GNU General Public License for more details. > */ > > +#include <linux/mutex.h> > #include <linux/usb/phy.h> > > /* Register definitions */ > @@ -301,7 +302,8 @@ struct samsung_usbphy_drvdata { > * @phy_type: Samsung SoCs specific phy types: #HOST > * #DEVICE > * @phy_usage: usage count for phy > - * @lock: lock for phy operations > + * @mutex: mutex for phy operations (usb2phy must sleep, so no spinlock!) > + * @hsic_reset_gpio: Active low GPIO that resets connected HSIC device > */ > struct samsung_usbphy { > struct usb_phy phy; > @@ -315,7 +317,8 @@ struct samsung_usbphy { > const struct samsung_usbphy_drvdata *drv_data; > enum samsung_usb_phy_type phy_type; > atomic_t phy_usage; > - spinlock_t lock; > + struct mutex mutex; > + int hsic_reset_gpio; > }; > > #define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy) > diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c > index 1011c16..2db2113 100644 > --- a/drivers/usb/phy/phy-samsung-usb2.c > +++ b/drivers/usb/phy/phy-samsung-usb2.c > @@ -24,6 +24,7 @@ > #include <linux/delay.h> > #include <linux/device.h> > #include <linux/err.h> > +#include <linux/gpio.h> > #include <linux/io.h> > #include <linux/of.h> > #include <linux/usb/otg.h> > @@ -43,15 +44,6 @@ static int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host) > return 0; > } > > -static bool exynos5_phyhost_is_on(void __iomem *regs) > -{ > - u32 reg; > - > - reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0); > - > - return !(reg & HOST_CTRL0_SIDDQ); > -} > - > static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) > { > void __iomem *regs = sphy->regs; > @@ -68,10 +60,8 @@ static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) > * the last consumer to disable it. > */ > > - atomic_inc(&sphy->phy_usage); > - > - if (exynos5_phyhost_is_on(regs)) { > - dev_info(sphy->dev, "Already power on PHY\n"); > + if (atomic_inc_return(&sphy->phy_usage) != 1) { > + dev_info(sphy->dev, "USB PHY already initialized\n"); > return; > } > > @@ -132,6 +122,13 @@ static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) > writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); > > /* HSIC phy configuration */ > + if (gpio_is_valid(sphy->hsic_reset_gpio)) { > + gpio_set_value(sphy->hsic_reset_gpio, 0); > + udelay(100); /* Keep reset as active/low for 100us */ > + gpio_set_value(sphy->hsic_reset_gpio, 1); > + usleep_range(4000, 10000); /* wait for device init */ > + } > + > phyhsic = (HSIC_CTRL_REFCLKDIV_12 | > HSIC_CTRL_REFCLKSEL | > HSIC_CTRL_PHYSWRST); > @@ -220,6 +217,9 @@ static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy *sphy) > writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); > writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); > > + if (gpio_is_valid(sphy->hsic_reset_gpio)) > + gpio_set_value(sphy->hsic_reset_gpio, 0); > + > phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); > phyhost |= (HOST_CTRL0_SIDDQ | > HOST_CTRL0_FORCESUSPEND | > @@ -267,7 +267,6 @@ static int samsung_usb2phy_init(struct usb_phy *phy) > { > struct samsung_usbphy *sphy; > struct usb_bus *host = NULL; > - unsigned long flags; > int ret = 0; > > sphy = phy_to_sphy(phy); > @@ -281,7 +280,7 @@ static int samsung_usb2phy_init(struct usb_phy *phy) > return ret; > } > > - spin_lock_irqsave(&sphy->lock, flags); > + mutex_lock(&sphy->mutex); > > if (host) { > /* setting default phy-type for USB 2.0 */ > @@ -304,7 +303,7 @@ static int samsung_usb2phy_init(struct usb_phy *phy) > /* Initialize usb phy registers */ > sphy->drv_data->phy_enable(sphy); > > - spin_unlock_irqrestore(&sphy->lock, flags); > + mutex_unlock(&sphy->mutex); > > /* Disable the phy clock */ > clk_disable_unprepare(sphy->clk); > @@ -319,7 +318,6 @@ static void samsung_usb2phy_shutdown(struct usb_phy *phy) > { > struct samsung_usbphy *sphy; > struct usb_bus *host = NULL; > - unsigned long flags; > > sphy = phy_to_sphy(phy); > > @@ -330,7 +328,7 @@ static void samsung_usb2phy_shutdown(struct usb_phy *phy) > return; > } > > - spin_lock_irqsave(&sphy->lock, flags); > + mutex_lock(&sphy->mutex); > > if (host) { > /* setting default phy-type for USB 2.0 */ > @@ -350,7 +348,7 @@ static void samsung_usb2phy_shutdown(struct usb_phy *phy) > else if (sphy->drv_data->set_isolation) > sphy->drv_data->set_isolation(sphy, true); > > - spin_unlock_irqrestore(&sphy->lock, flags); > + mutex_unlock(&sphy->mutex); > > clk_disable_unprepare(sphy->clk); > } > @@ -422,7 +420,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev) > sphy->phy.otg->phy = &sphy->phy; > sphy->phy.otg->set_host = samsung_usbphy_set_host; > > - spin_lock_init(&sphy->lock); > + mutex_init(&sphy->mutex); > > platform_set_drvdata(pdev, sphy); > > diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c > index 300e0cf..6ec3f08 100644 > --- a/drivers/usb/phy/phy-samsung-usb3.c > +++ b/drivers/usb/phy/phy-samsung-usb3.c > @@ -164,7 +164,6 @@ static void samsung_exynos5_usb3phy_disable(struct samsung_usbphy *sphy) > static int samsung_usb3phy_init(struct usb_phy *phy) > { > struct samsung_usbphy *sphy; > - unsigned long flags; > int ret = 0; > > sphy = phy_to_sphy(phy); > @@ -176,7 +175,7 @@ static int samsung_usb3phy_init(struct usb_phy *phy) > return ret; > } > > - spin_lock_irqsave(&sphy->lock, flags); > + mutex_lock(&sphy->mutex); > > /* setting default phy-type for USB 3.0 */ > samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); > @@ -188,7 +187,7 @@ static int samsung_usb3phy_init(struct usb_phy *phy) > /* Initialize usb phy registers */ > sphy->drv_data->phy_enable(sphy); > > - spin_unlock_irqrestore(&sphy->lock, flags); > + mutex_unlock(&sphy->mutex); > > /* Disable the phy clock */ > clk_disable_unprepare(sphy->clk); > @@ -202,7 +201,6 @@ static int samsung_usb3phy_init(struct usb_phy *phy) > static void samsung_usb3phy_shutdown(struct usb_phy *phy) > { > struct samsung_usbphy *sphy; > - unsigned long flags; > > sphy = phy_to_sphy(phy); > > @@ -211,7 +209,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy) > return; > } > > - spin_lock_irqsave(&sphy->lock, flags); > + mutex_lock(&sphy->mutex); > > /* setting default phy-type for USB 3.0 */ > samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); > @@ -223,7 +221,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy) > if (sphy->drv_data->set_isolation) > sphy->drv_data->set_isolation(sphy, true); > > - spin_unlock_irqrestore(&sphy->lock, flags); > + mutex_unlock(&sphy->mutex); > > clk_disable_unprepare(sphy->clk); > } > @@ -279,7 +277,7 @@ static int samsung_usb3phy_probe(struct platform_device *pdev) > if (sphy->ref_clk_freq < 0) > return -EINVAL; > > - spin_lock_init(&sphy->lock); > + mutex_init(&sphy->mutex); > > platform_set_drvdata(pdev, sphy); > > -- > 1.7.12.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Julius, On Wed, Jul 10, 2013 at 2:42 PM, Julius Werner <jwerner@chromium.org> wrote: > Hi Felipe, > > This is intended to pull down a reset signal line, not to switch power > to the device. I could implement that with the regulator framework > too, but I think that would just be confusing and harder to understand > without providing any benefit. It's really just a plain old GPIO. It seems that the reset gpio driver from Phillip Zabel would help in this case: http://permalink.gmane.org/gmane.linux.drivers.devicetree/36830 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Jingoo, Yeah, I followed that discussion back then, but it seems to have stalled a little (at least the HSIC patches haven't been picked up in any kernel.org repo yet to my knowledge). The problem is that I think these approaches cannot work reliably. I agree that it would be nice to control the HSIC device from its own driver, and have spent quite some time playing around with the usb/misc/usb3503.c driver to try to make this work... but there's a timing dependency here that you just can't model correctly with independent drivers. If the HSIC device is already active during boot (e.g. because it was used by firmware), there's always a chance that the USB stack will come up before the driver that resets it does. The device will be enumerated as normal, and when the other driver later pulls the reset signal the USB stack will not notice because there is no real disconnect detection on HSIC. Only when you eventually try to send another transfer to the device will you start to get timeouts, and the newly reset device will not be able to reenumerate because the host never asks it to. I really don't see how you could solve this without putting some kind of synchronization mechanism in the USB drivers. So this leaves ehci-s5p and phy-samsung-usb2 as the only possible places, and I chose the latter since all the host-side HSIC initialization is also there already. I think if you think of it as "reset whatever is on the other side of this PHY", it's okay to put it as an optional feature into the PHY driver. -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Friday, July 12, 2013 6:46 AM, Julius Werner wrote: > > Hi Jingoo, > > Yeah, I followed that discussion back then, but it seems to have > stalled a little (at least the HSIC patches haven't been picked up in > any kernel.org repo yet to my knowledge). > > The problem is that I think these approaches cannot work reliably. I > agree that it would be nice to control the HSIC device from its own > driver, and have spent quite some time playing around with the > usb/misc/usb3503.c driver to try to make this work... but there's a > timing dependency here that you just can't model correctly with > independent drivers. > > If the HSIC device is already active during boot (e.g. because it was > used by firmware), there's always a chance that the USB stack will > come up before the driver that resets it does. The device will be > enumerated as normal, and when the other driver later pulls the reset > signal the USB stack will not notice because there is no real > disconnect detection on HSIC. Only when you eventually try to send > another transfer to the device will you start to get timeouts, and the > newly reset device will not be able to reenumerate because the host > never asks it to. > > I really don't see how you could solve this without putting some kind > of synchronization mechanism in the USB drivers. So this leaves > ehci-s5p and phy-samsung-usb2 as the only possible places, and I chose > the latter since all the host-side HSIC initialization is also there > already. I think if you think of it as "reset whatever is on the other > side of this PHY", it's okay to put it as an optional feature into the > PHY driver. CC'ed Tomasz Figa, Dongjin Kim, Yulgon Kim Hi Tomasz, Dongjin, Julius Werner wants to put 'SMSC 3503 hub reset on Arndale board' to 'phy-samsung-usb*.c' files, because there is a timing dependency above mentioned. The following is the original patch sent by Julius Werner two day ago. (http://www.spinics.net/lists/linux-samsung-soc/msg20250.html) Previously, Olof mentioned that 'drivers/platform/arm/' would be used. (http://patches.linaro.org/16856/) Also, another way was mentioned by Fabio Estevam, using 'drivers/reset/gpio-reset.c' which is not merged yet. (http://permalink.gmane.org/gmane.linux.drivers.devicetree/36830) I think that 'phy-samsung-usb*.c' files are not a good place. However, Julius Werner's comment looks reasonable enough. If you have a comment, please feel free to share it. :) Thank you. Best regards, Jingoo Han -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi, On Wed, Jul 10, 2013 at 10:42:27AM -0700, Julius Werner wrote: > Hi Felipe, > > This is intended to pull down a reset signal line, not to switch power > to the device. I could implement that with the regulator framework > too, but I think that would just be confusing and harder to understand > without providing any benefit. It's really just a plain old GPIO. alright, in that case how about using drivers/reset/ ?
Hi, On Friday 12 of July 2013 09:48:54 Jingoo Han wrote: > On Friday, July 12, 2013 6:46 AM, Julius Werner wrote: > > Hi Jingoo, > > > > Yeah, I followed that discussion back then, but it seems to have > > stalled a little (at least the HSIC patches haven't been picked up in > > any kernel.org repo yet to my knowledge). > > > > The problem is that I think these approaches cannot work reliably. I > > agree that it would be nice to control the HSIC device from its own > > driver, and have spent quite some time playing around with the > > usb/misc/usb3503.c driver to try to make this work... but there's a > > timing dependency here that you just can't model correctly with > > independent drivers. > > > > If the HSIC device is already active during boot (e.g. because it was > > used by firmware), there's always a chance that the USB stack will > > come up before the driver that resets it does. The device will be > > enumerated as normal, and when the other driver later pulls the reset > > signal the USB stack will not notice because there is no real > > disconnect detection on HSIC. Only when you eventually try to send > > another transfer to the device will you start to get timeouts, and the > > newly reset device will not be able to reenumerate because the host > > never asks it to. > > > > I really don't see how you could solve this without putting some kind > > of synchronization mechanism in the USB drivers. So this leaves > > ehci-s5p and phy-samsung-usb2 as the only possible places, and I chose > > the latter since all the host-side HSIC initialization is also there > > already. I think if you think of it as "reset whatever is on the other > > side of this PHY", it's okay to put it as an optional feature into the > > PHY driver. > > CC'ed Tomasz Figa, Dongjin Kim, Yulgon Kim > > > Hi Tomasz, Dongjin, > > Julius Werner wants to put 'SMSC 3503 hub reset on Arndale board' > to 'phy-samsung-usb*.c' files, because there is a timing dependency > above mentioned. > The following is the original patch sent by Julius Werner two day ago. > (http://www.spinics.net/lists/linux-samsung-soc/msg20250.html) Well, I think this is simply broken. Following are the reasons why I think so: a) you can use the smsc3503 chip on any USB/HSIC controller and with any USB/HSIC PHY, so you would have to add such reset GPIO to _every_ PHY or controller driver, b) you might want to use other USB/HSIC hubs like this one that requires some initialization sequence, other than just toggling a GPIO, so you would have to add cases for all of those hubs or other chips in _every_ PHY or controller driver. > Previously, Olof mentioned that 'drivers/platform/arm/' would be used. > (http://patches.linaro.org/16856/) > > Also, another way was mentioned by Fabio Estevam, using > 'drivers/reset/gpio-reset.c' which is not merged yet. > (http://permalink.gmane.org/gmane.linux.drivers.devicetree/36830) > > I think that 'phy-samsung-usb*.c' files are not a good place. > However, Julius Werner's comment looks reasonable enough. I can see this problem almost equivalent to the problem with on-board WLAN adapters connected using SDIO. Those adapters require some kind of power on sequence before they can be enumerated using standard MMC/SDIO mechanisms and so does this USB/HSIC hub. So basically this is a thing that we should consider on a more generic level, not just for this particular single chip. CCing some extra people to increase chance of getting more opinions on this. Best regards, Tomasz -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 12 July 2013 12:27, Felipe Balbi <balbi@ti.com> wrote: > Hi, > > On Wed, Jul 10, 2013 at 10:42:27AM -0700, Julius Werner wrote: >> Hi Felipe, >> >> This is intended to pull down a reset signal line, not to switch power >> to the device. I could implement that with the regulator framework >> too, but I think that would just be confusing and harder to understand >> without providing any benefit. It's really just a plain old GPIO. > > alright, in that case how about using drivers/reset/ ? > IIUC, reset-gpio driver only provides APIs for reset controls (reset, assert, deassert). We still need to find out the location from where we would be calling the reset function.
On Tue, Aug 13, 2013 at 02:11:27PM +0530, Tushar Behera wrote: > On 12 July 2013 12:27, Felipe Balbi <balbi@ti.com> wrote: > > Hi, > > > > On Wed, Jul 10, 2013 at 10:42:27AM -0700, Julius Werner wrote: > >> Hi Felipe, > >> > >> This is intended to pull down a reset signal line, not to switch power > >> to the device. I could implement that with the regulator framework > >> too, but I think that would just be confusing and harder to understand > >> without providing any benefit. It's really just a plain old GPIO. > > > > alright, in that case how about using drivers/reset/ ? > > > > IIUC, reset-gpio driver only provides APIs for reset controls (reset, > assert, deassert). We still need to find out the location from where > we would be calling the reset function. that's fair, but at least you reuse a bunch of boilerplate code to claim the GPIO, set proper direction and value. No need to duplicate that in your driver.
On 28 August 2013 00:14, Felipe Balbi <balbi@ti.com> wrote: > On Tue, Aug 13, 2013 at 02:11:27PM +0530, Tushar Behera wrote: >> On 12 July 2013 12:27, Felipe Balbi <balbi@ti.com> wrote: >> > Hi, >> > >> > On Wed, Jul 10, 2013 at 10:42:27AM -0700, Julius Werner wrote: >> >> Hi Felipe, >> >> >> >> This is intended to pull down a reset signal line, not to switch power >> >> to the device. I could implement that with the regulator framework >> >> too, but I think that would just be confusing and harder to understand >> >> without providing any benefit. It's really just a plain old GPIO. >> > >> > alright, in that case how about using drivers/reset/ ? >> > >> >> IIUC, reset-gpio driver only provides APIs for reset controls (reset, >> assert, deassert). We still need to find out the location from where >> we would be calling the reset function. > > that's fair, but at least you reuse a bunch of boilerplate code to claim > the GPIO, set proper direction and value. No need to duplicate that in > your driver. > SMSC3503 driver code was recently updated by Mark Brown [1] which allows the device to work even if it is not connected to I2C bus. The timing is still an issue though [2]. With this USB works on linux-next, but surely that [2] is not the solution. [1] http://comments.gmane.org/gmane.linux.usb.general/92061 [2] https://lkml.org/lkml/2013/8/14/814
I've tried to get the 3503 driver to work in my case for quite some time, but ultimately gave up. For me, playing around with the load order was not enough to solve all issues. When you try to build a permanent, clean solution for this, you should definitely also test the case where the hub has already been initialized and configured by firmware before the kernel booted, because that brought on another bunch of issues for me. I think it ultimately only works reliably when you first reset the hub, then reset the HSIC port on the PHY side before the USB core gets a chance to talk to it again (thus one of the drivers needs to be directly connected to and call the other). -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt index 33fd354..82e2e16 100644 --- a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt +++ b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt @@ -31,6 +31,12 @@ Optional properties: - ranges: allows valid translation between child's address space and parent's address space. +- samsung,hsic-reset-gpio: an active low GPIO pin that resets a device + connected to the HSIC port. Useful for things like + an on-board SMSC3503 hub. +- pinctrl-0: Pin control group containing the HSIC reset GPIO pin. +- pinctrl-names: Should contain only one value - "default". + - The child node 'usbphy-sys' to the node 'usbphy' is for the system controller interface for usb-phy. It should provide the following information required by usb-phy controller to control phy. @@ -56,6 +62,10 @@ Example: clocks = <&clock 2>, <&clock 305>; clock-names = "xusbxti", "otg"; + samsung,hsic-reset-gpio = <&gpx2 4 1>; + pinctrl-names = "default"; + pinctrl-0 = <&hsic_reset>; + usbphy-sys { /* USB device and host PHY_CONTROL registers */ reg = <0x10020704 0x8>; diff --git a/drivers/usb/phy/phy-samsung-usb.c b/drivers/usb/phy/phy-samsung-usb.c index ac025ca..23f1d70 100644 --- a/drivers/usb/phy/phy-samsung-usb.c +++ b/drivers/usb/phy/phy-samsung-usb.c @@ -27,6 +27,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_gpio.h> #include <linux/usb/samsung_usb_phy.h> #include "phy-samsung-usb.h" @@ -58,6 +59,22 @@ int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy) if (sphy->sysreg == NULL) dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n"); + /* + * Some boards have a separate active-low reset GPIO for their HSIC USB + * devices. If they don't, this will just stay at an invalid value and + * the init code will ignore it. + */ + sphy->hsic_reset_gpio = of_get_named_gpio(sphy->dev->of_node, + "samsung,hsic-reset-gpio", 0); + if (gpio_is_valid(sphy->hsic_reset_gpio)) { + if (devm_gpio_request_one(sphy->dev, sphy->hsic_reset_gpio, + GPIOF_OUT_INIT_LOW, "samsung_hsic_reset")) { + dev_err(sphy->dev, "can't request hsic reset gpio %d\n", + sphy->hsic_reset_gpio); + sphy->hsic_reset_gpio = -EINVAL; + } + } + of_node_put(usbphy_sys); return 0; diff --git a/drivers/usb/phy/phy-samsung-usb.h b/drivers/usb/phy/phy-samsung-usb.h index 68771bf..0703878 100644 --- a/drivers/usb/phy/phy-samsung-usb.h +++ b/drivers/usb/phy/phy-samsung-usb.h @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include <linux/mutex.h> #include <linux/usb/phy.h> /* Register definitions */ @@ -301,7 +302,8 @@ struct samsung_usbphy_drvdata { * @phy_type: Samsung SoCs specific phy types: #HOST * #DEVICE * @phy_usage: usage count for phy - * @lock: lock for phy operations + * @mutex: mutex for phy operations (usb2phy must sleep, so no spinlock!) + * @hsic_reset_gpio: Active low GPIO that resets connected HSIC device */ struct samsung_usbphy { struct usb_phy phy; @@ -315,7 +317,8 @@ struct samsung_usbphy { const struct samsung_usbphy_drvdata *drv_data; enum samsung_usb_phy_type phy_type; atomic_t phy_usage; - spinlock_t lock; + struct mutex mutex; + int hsic_reset_gpio; }; #define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy) diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c index 1011c16..2db2113 100644 --- a/drivers/usb/phy/phy-samsung-usb2.c +++ b/drivers/usb/phy/phy-samsung-usb2.c @@ -24,6 +24,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/gpio.h> #include <linux/io.h> #include <linux/of.h> #include <linux/usb/otg.h> @@ -43,15 +44,6 @@ static int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -static bool exynos5_phyhost_is_on(void __iomem *regs) -{ - u32 reg; - - reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0); - - return !(reg & HOST_CTRL0_SIDDQ); -} - static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) { void __iomem *regs = sphy->regs; @@ -68,10 +60,8 @@ static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) * the last consumer to disable it. */ - atomic_inc(&sphy->phy_usage); - - if (exynos5_phyhost_is_on(regs)) { - dev_info(sphy->dev, "Already power on PHY\n"); + if (atomic_inc_return(&sphy->phy_usage) != 1) { + dev_info(sphy->dev, "USB PHY already initialized\n"); return; } @@ -132,6 +122,13 @@ static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); /* HSIC phy configuration */ + if (gpio_is_valid(sphy->hsic_reset_gpio)) { + gpio_set_value(sphy->hsic_reset_gpio, 0); + udelay(100); /* Keep reset as active/low for 100us */ + gpio_set_value(sphy->hsic_reset_gpio, 1); + usleep_range(4000, 10000); /* wait for device init */ + } + phyhsic = (HSIC_CTRL_REFCLKDIV_12 | HSIC_CTRL_REFCLKSEL | HSIC_CTRL_PHYSWRST); @@ -220,6 +217,9 @@ static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy *sphy) writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); + if (gpio_is_valid(sphy->hsic_reset_gpio)) + gpio_set_value(sphy->hsic_reset_gpio, 0); + phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); phyhost |= (HOST_CTRL0_SIDDQ | HOST_CTRL0_FORCESUSPEND | @@ -267,7 +267,6 @@ static int samsung_usb2phy_init(struct usb_phy *phy) { struct samsung_usbphy *sphy; struct usb_bus *host = NULL; - unsigned long flags; int ret = 0; sphy = phy_to_sphy(phy); @@ -281,7 +280,7 @@ static int samsung_usb2phy_init(struct usb_phy *phy) return ret; } - spin_lock_irqsave(&sphy->lock, flags); + mutex_lock(&sphy->mutex); if (host) { /* setting default phy-type for USB 2.0 */ @@ -304,7 +303,7 @@ static int samsung_usb2phy_init(struct usb_phy *phy) /* Initialize usb phy registers */ sphy->drv_data->phy_enable(sphy); - spin_unlock_irqrestore(&sphy->lock, flags); + mutex_unlock(&sphy->mutex); /* Disable the phy clock */ clk_disable_unprepare(sphy->clk); @@ -319,7 +318,6 @@ static void samsung_usb2phy_shutdown(struct usb_phy *phy) { struct samsung_usbphy *sphy; struct usb_bus *host = NULL; - unsigned long flags; sphy = phy_to_sphy(phy); @@ -330,7 +328,7 @@ static void samsung_usb2phy_shutdown(struct usb_phy *phy) return; } - spin_lock_irqsave(&sphy->lock, flags); + mutex_lock(&sphy->mutex); if (host) { /* setting default phy-type for USB 2.0 */ @@ -350,7 +348,7 @@ static void samsung_usb2phy_shutdown(struct usb_phy *phy) else if (sphy->drv_data->set_isolation) sphy->drv_data->set_isolation(sphy, true); - spin_unlock_irqrestore(&sphy->lock, flags); + mutex_unlock(&sphy->mutex); clk_disable_unprepare(sphy->clk); } @@ -422,7 +420,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev) sphy->phy.otg->phy = &sphy->phy; sphy->phy.otg->set_host = samsung_usbphy_set_host; - spin_lock_init(&sphy->lock); + mutex_init(&sphy->mutex); platform_set_drvdata(pdev, sphy); diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c index 300e0cf..6ec3f08 100644 --- a/drivers/usb/phy/phy-samsung-usb3.c +++ b/drivers/usb/phy/phy-samsung-usb3.c @@ -164,7 +164,6 @@ static void samsung_exynos5_usb3phy_disable(struct samsung_usbphy *sphy) static int samsung_usb3phy_init(struct usb_phy *phy) { struct samsung_usbphy *sphy; - unsigned long flags; int ret = 0; sphy = phy_to_sphy(phy); @@ -176,7 +175,7 @@ static int samsung_usb3phy_init(struct usb_phy *phy) return ret; } - spin_lock_irqsave(&sphy->lock, flags); + mutex_lock(&sphy->mutex); /* setting default phy-type for USB 3.0 */ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); @@ -188,7 +187,7 @@ static int samsung_usb3phy_init(struct usb_phy *phy) /* Initialize usb phy registers */ sphy->drv_data->phy_enable(sphy); - spin_unlock_irqrestore(&sphy->lock, flags); + mutex_unlock(&sphy->mutex); /* Disable the phy clock */ clk_disable_unprepare(sphy->clk); @@ -202,7 +201,6 @@ static int samsung_usb3phy_init(struct usb_phy *phy) static void samsung_usb3phy_shutdown(struct usb_phy *phy) { struct samsung_usbphy *sphy; - unsigned long flags; sphy = phy_to_sphy(phy); @@ -211,7 +209,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy) return; } - spin_lock_irqsave(&sphy->lock, flags); + mutex_lock(&sphy->mutex); /* setting default phy-type for USB 3.0 */ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); @@ -223,7 +221,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy) if (sphy->drv_data->set_isolation) sphy->drv_data->set_isolation(sphy, true); - spin_unlock_irqrestore(&sphy->lock, flags); + mutex_unlock(&sphy->mutex); clk_disable_unprepare(sphy->clk); } @@ -279,7 +277,7 @@ static int samsung_usb3phy_probe(struct platform_device *pdev) if (sphy->ref_clk_freq < 0) return -EINVAL; - spin_lock_init(&sphy->lock); + mutex_init(&sphy->mutex); platform_set_drvdata(pdev, sphy);
This patch adds support for a new 'samsung,hsic-reset-gpio' in the device tree, which will be interpreted as an active-low reset pin during PHY initialization when it exists. Useful for intergrated HSIC devices like an SMSC 3503 hub. It is necessary to add this directly to the PHY initialization to get the timing right, since resetting a HSIC device after it has already been enumerated can confuse the USB stack. Also fixes PHY semaphore code to make sure we always go through the setup at least once, even if it was already turned on (e.g. by firmware), and changes a spinlock to a mutex to allow sleeping in the critical section. Change-Id: Ieecac52c27daa7a17a7ed3b2863ddba3aeb8d16f Signed-off-by: Julius Werner <jwerner@chromium.org> --- .../devicetree/bindings/usb/samsung-usbphy.txt | 10 ++++++ drivers/usb/phy/phy-samsung-usb.c | 17 ++++++++++ drivers/usb/phy/phy-samsung-usb.h | 7 ++-- drivers/usb/phy/phy-samsung-usb2.c | 38 ++++++++++------------ drivers/usb/phy/phy-samsung-usb3.c | 12 +++---- 5 files changed, 55 insertions(+), 29 deletions(-)