summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsupriya karanth <supriya.karanth@stericsson.com>2012-05-22 09:37:00 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:25:19 +0200
commit2b85348ec0be48a89fb2689bc59d943fbee8a625 (patch)
tree0f7b9caec8ac1cf2f66087f98f791c1b43d4df01
parent49ad144fbf2abcc415847975e79f0ef9bb5e78c6 (diff)
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 <supriya.karanth@stericsson.com>
-rw-r--r--drivers/usb/musb/musb_core.c35
-rw-r--r--drivers/usb/musb/musb_debugfs.c1
-rw-r--r--drivers/usb/musb/ux500.c12
3 files changed, 48 insertions, 0 deletions
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) {