From 2b85348ec0be48a89fb2689bc59d943fbee8a625 Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Tue, 22 May 2012 09:37:00 +0200 Subject: usb: musb: SW workaround for USB host issue For snowball in HOST mode, the eye diagram is facing high distortion in high speed use cases. This patch allows the user to use an external charge pump instead of the internal one to generate the Vbus voltage. This can be done by setting a sysfs entry. The external VBUS is OFF by default and can be made ON by setting the sysfs entry inorder to enumerate high speed devices. Signed-off-by: supriya karanth --- drivers/usb/musb/musb_core.c | 35 +++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_debugfs.c | 1 + drivers/usb/musb/ux500.c | 12 ++++++++++++ 3 files changed, 48 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1ab2fd8c3e9..2923752b858 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1767,10 +1767,45 @@ musb_srp_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); +static ssize_t +ux500_set_extvbus(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + unsigned short extvbus; + + if (sscanf(buf, "%hu", &extvbus) != 1 + || ((extvbus != 1) && (extvbus != 0))) { + dev_err(dev, "Invalid value EXTVBUS must be 1 or 0\n"); + return -EINVAL; + } + + plat->extvbus = extvbus; + + return n; +} + +static ssize_t +ux500_get_extvbus(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + int extvbus; + + /* FIXME get_vbus_status() is normally #defined as false... + * and is effectively TUSB-specific. + */ + extvbus = plat->extvbus; + + return sprintf(buf, "EXTVBUS is %s\n", + extvbus ? "on" : "off"); +} +static DEVICE_ATTR(extvbus, 0644, ux500_get_extvbus, ux500_set_extvbus); + static struct attribute *musb_attributes[] = { &dev_attr_mode.attr, &dev_attr_vbus.attr, &dev_attr_srp.attr, + &dev_attr_extvbus.attr, NULL }; diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 40a37c91cc1..19e3c91c22e 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -68,6 +68,7 @@ static const struct musb_register_map musb_regmap[] = { { "RxFIFOadd", 0x66, 16 }, { "VControl", 0x68, 32 }, { "HWVers", 0x6C, 16 }, + { "EXTVBUS", 0x70, 8 }, { "EPInfo", 0x78, 8 }, { "RAMInfo", 0x79, 8 }, { "LinkInfo", 0x7A, 8 }, diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 2f089ddcd46..c1a205cd5e3 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -311,6 +311,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) u8 devctl; unsigned long timeout = jiffies + msecs_to_jiffies(1000); int ret = 1; + struct musb_hdrc_platform_data *plat = musb->controller->platform_data; #ifdef CONFIG_USB_OTG_20 int val = 0; #endif @@ -323,6 +324,17 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) val |= 0x1C; musb_writeb(musb->mregs, MUSB_MISC, val); #endif + + /* Use EXTVBUS */ + u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); + if (plat->extvbus) { + busctl |= MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); + } else { + busctl &= ~MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); + } + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { -- cgit v1.2.3