Hi, I've been playing about with this for the last few days. Unfortunately
it doesn't work correctly, and I'm running out of ideas to try. Therefore
I'm posting my progress so far here in case anyone can shed some light....
Note that this patch is against the HTC Hero kernel source, but I imagine it
would work for the G1 which is MSM7201A based as well.
First of all, I don't have the docs for the MSM7201A. However, from looking
at the gadget support code, its obviously using the same EHCI USB core as
various freescale CPUs. There are docs available for these, such as the
MPC5121. The reference manual for that is available here:
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPC5121e&nodeId=0162468rH3DgbNGrmC22FA&fpsp=1&tab=Documentation_Tab
Note that the MSM7201a appears to have a slightly newer core; the REVISION
field in the MODULE ID register is newer. I've not yet looked for docs on a
newer CPU with this newer core revision, but that will be my next step.
The USB transceiver is an SMSC USB3316. Unfortunately, again, I do not have
docs for this. However, register level docs on the USB3320 series (which
seems very closely related) are available from here:
http://www.smsc.com/index.php?tid=143&pid=211&cid=&tab=4
Additionally, you'll need a specially hacked USB cable which deals with the
fact you're using a USB B connector as a usb host, and also supplies power
to downstream USB devices (I doubt the hero can /output/ power on the VBUS
line. Even if it can, I've no idea how to switch it to do so) . I happened
to have one of these made up form my old Nokia N770 so I just repurposed
that. There's information about this sort of thing at the openmoko project:
http://wiki.openmoko.org/wiki/Specialized_USB_cables
The attached patch adds the necessary glue to get the EHCI host controller
running. I've not bothered to implement any gadget/function coexistence code
yet, so you'd need to disable those to try it out.
So: the EHCI host controller starts up happily, and can even see devices
being plugged in. The problem is it doesn't seem to be able to communicate
with the usb devices. I get lots of -EPROTO (-71) errors (as in the attached
connect-error.txt file). I've tried everything I can think of, but am
hampered by (a) lacking specific documentation and (b) not knowing how the
hero/USB port is wired. It's even possible that the hero is missing some
vital piece of hardware to support host mode :(
The USB3316 appears to be able to swap the D+/D- lines about by changing a
register setting. I've tried this in case I had them the wrong way round; it
changed the errors, but didn't really help. Also, note that the openmoko
site talks about missing 15k resistors causing exactly this sort of error.
However, the USB3316 has these built in, and they're software controllable.
--
unsubscribe: [email protected]
website: http://groups.google.com/group/android-kernel
[ 109.957824] select 211 (app_process), adj 15, size 2952, to kill
[ 109.958099] send sigkill to 211 (app_process), adj 15, size 2952
[ 110.987915] select 299 (app_process), adj 15, size 2905, to kill
[ 110.988189] select 433 (app_process), adj 15, size 2939, to kill
[ 110.988586] send sigkill to 433 (app_process), adj 15, size 2939
[ 111.916046] select 299 (app_process), adj 15, size 2905, to kill
[ 111.916473] send sigkill to 299 (app_process), adj 15, size 2905
[ 112.876983] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 112.887390] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
[ 112.887695] msm_hsusb msm_hsusb: GetStatus port 1 status 84001403 POWER
sig=k CSC CONNECT
[ 112.888153] hub 1-0:1.0: port 1, status 0301, change 0001, 1.5 Mb/s
[ 112.888427] msm_hsusb msm_hsusb: GetStatus port 1 status 84001401 POWER
sig=k CONNECT
[ 112.927490] msm_hsusb msm_hsusb: GetStatus port 1 status 84001401 POWER
sig=k CONNECT
[ 112.967468] msm_hsusb msm_hsusb: GetStatus port 1 status 84001401 POWER
sig=k CONNECT
[ 113.007476] msm_hsusb msm_hsusb: GetStatus port 1 status 84001401 POWER
sig=k CONNECT
[ 113.047454] msm_hsusb msm_hsusb: GetStatus port 1 status 84001401 POWER
sig=k CONNECT
[ 113.047912] hub 1-0:1.0: debounce: port 1: total 100ms stable 100ms status
0x301
[ 113.048370] msm_hsusb msm_hsusb: port 1 reset
[ 113.103637] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 113.107482] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 113.167480] usb 1-1: new low speed USB device using msm_hsusb and address 6
[ 113.167968] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b060 [qh 00000000]
[ 113.169677] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.169952] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.170471] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b120 [qh ffc4a080]
[ 113.171661] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.171936] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.172424] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b180 [qh ffc4a080]
[ 113.173675] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.173919] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.174407] msm_hsusb msm_hsusb: port 1 reset
[ 113.187408] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 113.227478] msm_hsusb msm_hsusb: port 1 high speed
[ 113.227935] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 113.228363] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 113.287597] usb 1-1: device descriptor read/64, error -71
[ 113.397552] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b060 [qh ffc4a080]
[ 113.399688] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.400146] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.400543] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b120 [qh ffc4a080]
[ 113.401702] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.402160] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.402526] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b180 [qh ffc4a080]
[ 113.403686] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.404144] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.404479] msm_hsusb msm_hsusb: port 1 reset
[ 113.417449] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 113.457519] msm_hsusb msm_hsusb: port 1 high speed
[ 113.457946] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 113.458221] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 113.517517] usb 1-1: device descriptor read/64, error -71
[ 113.627593] msm_hsusb msm_hsusb: port 1 reset
[ 113.683074] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 113.687469] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 113.747467] usb 1-1: new low speed USB device using msm_hsusb and address 7
[ 113.747802] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b180 [qh 00000000]
[ 113.749694] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.750152] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.750549] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b0c0 [qh ffc4a080]
[ 113.751678] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.752136] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.752502] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b120 [qh ffc4a080]
[ 113.753692] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.754119] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.754455] msm_hsusb msm_hsusb: port 1 reset
[ 113.767425] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 113.807403] msm_hsusb msm_hsusb: port 1 high speed
[ 113.807830] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 113.808105] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 113.867492] usb 1-1: device descriptor read/64, error -71
[ 113.977508] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b180 [qh ffc4a080]
[ 113.979705] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.979980] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.980560] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b0c0 [qh ffc4a080]
[ 113.981689] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.981964] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.982513] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 64,
qtd ffc4b120 [qh ffc4a080]
[ 113.983703] msm_hsusb msm_hsusb: irq status 0001 INT
[ 113.983978] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status 0
len 0/64
[ 113.984497] msm_hsusb msm_hsusb: port 1 reset
[ 113.997406] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.037475] msm_hsusb msm_hsusb: port 1 high speed
[ 114.037750] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 114.038177] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 114.097503] usb 1-1: device descriptor read/64, error -71
[ 114.208007] msm_hsusb msm_hsusb: port 1 reset
[ 114.263305] msm_hsusb msm_hsusb: irq status 0004 PCD
[ 114.267608] msm_hsusb msm_hsusb: GetStatus port 1 status 84001405 POWER
sig=k PE CONNECT
[ 114.327575] usb 1-1: new low speed USB device using msm_hsusb and address 8
[ 114.328063] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 0,
qtd ffc4b120 [qh 00000000]
[ 114.329711] msm_hsusb msm_hsusb: irq status 0001 INT
[ 114.329986] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0out status
0 len 0/0
[ 114.330688] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.357604] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 8,
qtd ffc4b120 [qh 00000000]
[ 114.358703] msm_hsusb msm_hsusb: irq status 0002 ERR
[ 114.359130] msm_hsusb msm_hsusb: devpath 1 ep0in 3strikes
[ 114.359344] msm_hsusb msm_hsusb: dev8 ep0in qtd token 00080248 --> status
-71
[ 114.359771] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status
-71 len 0/8
[ 114.360229] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.366699] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 8,
qtd ffc4b060 [qh ffc4a080]
[ 114.367675] msm_hsusb msm_hsusb: irq status 0002 ERR
[ 114.367950] msm_hsusb msm_hsusb: devpath 1 ep0in 3strikes
[ 114.368347] msm_hsusb msm_hsusb: dev8 ep0in qtd token 00080248 --> status
-71
[ 114.368560] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status
-71 len 0/8
[ 114.369018] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.377929] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 8,
qtd ffc4b0c0 [qh ffc4a080]
[ 114.379699] msm_hsusb msm_hsusb: irq status 0002 ERR
[ 114.380126] msm_hsusb msm_hsusb: devpath 1 ep0in 3strikes
[ 114.380340] msm_hsusb msm_hsusb: dev8 ep0in qtd token 00080248 --> status -71
[ 114.380767] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status
-71 len 0/8
[ 114.381225] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.381652] usb 1-1: device descriptor read/8, error -71
[ 114.507537] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 8,
qtd ffc4b120 [qh ffc4a080]
[ 114.509704] msm_hsusb msm_hsusb: irq status 0002 ERR
[ 114.510162] msm_hsusb msm_hsusb: devpath 1 ep0in 3strikes
[ 114.510375] msm_hsusb msm_hsusb: dev8 ep0in qtd token 00080248 --> status -71
[ 114.510772] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status
-71 len 0/8
[ 114.511260] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.511596] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 8,
qtd ffc4b060 [qh ffc4a080]
[ 114.512695] msm_hsusb msm_hsusb: irq status 0002 ERR
[ 114.512939] msm_hsusb msm_hsusb: devpath 1 ep0in 3strikes
[ 114.513336] msm_hsusb msm_hsusb: dev8 ep0in qtd token 00080248 --> status -71
[ 114.513580] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status
-71 len 0/8
[ 114.514038] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.514343] msm_hsusb msm_hsusb: submit_async 1 urb cb49a0a0 ep0out len 8,
qtd ffc4b0c0 [qh ffc4a080]
[ 114.515686] msm_hsusb msm_hsusb: irq status 0002 ERR
[ 114.516113] msm_hsusb msm_hsusb: devpath 1 ep0in 3strikes
[ 114.516326] msm_hsusb msm_hsusb: dev8 ep0in qtd token 00080248 --> status -71
[ 114.516754] msm_hsusb msm_hsusb: ehci_urb_done 1 urb cb49a0a0 ep0in status
-71 len 0/8
[ 114.517211] msm_hsusb msm_hsusb: irq status 0020 IAA
[ 114.518035] usb 1-1: device descriptor read/8, error -71
[ 114.627593] msm_hsusb msm_hsusb: port 1 reset
--- kernel_hero/arch/arm/mach-msm/devices.c 2009-10-22 07:39:39.000000000 +0100
+++ kernel_hero.patched/arch/arm/mach-msm/devices.c 2010-01-31 17:55:42.835673987 +0000
@@ -158,6 +158,7 @@
/* adjust eye diagram, disable vbusvalid interrupts */
static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1, 0x0D, 0x1, 0x10, -1 };
+#ifdef CONFIG_USB_FUNCTION
static char *usb_functions[] = {
#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS)
@@ -227,10 +228,12 @@
},
};
+#endif
struct msm_hsusb_platform_data msm_hsusb_pdata = {
.phy_reset = internal_phy_reset,
.phy_init_seq = hsusb_phy_init_seq,
+#ifdef CONFIG_USB_FUNCTION
.vendor_id = 0x0bb4,
.product_id = 0x0c02,
.version = 0x0100,
@@ -241,6 +244,7 @@
.num_functions = ARRAY_SIZE(usb_functions),
.products = usb_products,
.num_products = ARRAY_SIZE(usb_products),
+#endif
};
static struct resource resources_hsusb[] = {
@@ -1123,6 +1127,7 @@
return mfg_mode;
}
+#ifdef CONFIG_USB_FUNCTION
static int __init board_serialno_setup(char *serialno)
{
if (board_mfg_mode() || !strlen(serialno))
@@ -1133,6 +1138,7 @@
}
__setup("androidboot.serialno=", board_serialno_setup);
+#endif
EXPORT_SYMBOL(board_mfg_mode);
static char *keycap_tag = NULL;
--- kernel_hero/arch/arm/mach-msm/htc_battery.c 2009-10-22 07:39:39.000000000 +0100
+++ kernel_hero.patched/arch/arm/mach-msm/htc_battery.c 2010-01-31 17:57:51.915655870 +0000
@@ -205,12 +205,14 @@
},
};
-static void usb_status_notifier_func(int online);
static int g_usb_online;
+#ifdef CONFIG_USB_FUNCTION
+static void usb_status_notifier_func(int online);
static struct t_usb_status_notifier usb_status_notifier = {
.name = "htc_battery",
.func = usb_status_notifier_func,
};
+#endif
/* -------------------------------------------------------------------------- */
/* For sleep charging screen. */
@@ -476,6 +478,7 @@
return rc;
}
+#ifdef CONFIG_USB_FUNCTION
/* A9 reports USB charging when helf AC cable in and China AC charger. */
/* Work arround: notify userspace AC charging first,
and notify USB charging again when receiving usb connected notificaiton from usb driver. */
@@ -496,6 +499,8 @@
}
mutex_unlock(&htc_batt_info.lock);
}
+#endif
+
static int htc_get_batt_info(struct battery_info_reply *buffer)
{
struct rpc_request_hdr req;
@@ -1231,7 +1236,9 @@
wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
mutex_init(&htc_batt_info.lock);
mutex_init(&htc_batt_info.rpc_lock);
+#ifdef CONFIG_USB_FUNCTION
usb_register_notifier(&usb_status_notifier);
+#endif
msm_rpc_create_server(&battery_server);
platform_driver_register(&htc_battery_driver);
batt_register_client(&batt_notify);
--- kernel_hero/drivers/usb/function/Kconfig 2009-10-22 07:39:58.000000000 +0100
+++ kernel_hero.patched/drivers/usb/function/Kconfig 2010-02-07 18:50:28.137447755 +0000
@@ -14,7 +14,7 @@
config USB_FUNCTION_MSM_HSUSB
boolean "MSM7K Highspeed USB Peripheral Controller"
- depends on ARCH_MSM7XXX
+ depends on ARCH_MSM7XXX && (!USB_EHCI_MSM7201)
endchoice
--- kernel_hero/drivers/usb/host/ehci-hcd.c 2009-10-22 07:39:59.000000000 +0100
+++ kernel_hero.patched/drivers/usb/host/ehci-hcd.c 2010-02-07 13:53:18.487470510 +0000
@@ -65,9 +65,9 @@
static const char hcd_name [] = "ehci_hcd";
-
-#undef VERBOSE_DEBUG
-#undef EHCI_URB_TRACE
+#define DEBUG 1
+#define VERBOSE_DEBUG 1
+#define EHCI_URB_TRACE 1
#ifdef DEBUG
#define EHCI_STATS
@@ -1040,6 +1040,11 @@
#define PLATFORM_DRIVER ixp4xx_ehci_driver
#endif
+#ifdef CONFIG_ARCH_MSM7XXX
+#include "ehci-msm7201.c"
+#define PLATFORM_DRIVER ehci_msm7201_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
#error "missing bus glue for ehci-hcd"
--- kernel_hero/drivers/usb/host/ehci-msm7201.c 1970-01-01 01:00:00.000000000 +0100
+++ kernel_hero.patched/drivers/usb/host/ehci-msm7201.c 2010-02-07 18:09:44.331565454 +0000
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2010 Andrew de Quincey
+ *
+ * (heavily) based on ehci-fsl.c, which is:
+ *
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Ported to 834x by Randy Vinson <[email protected]> using code provided
+ * by Hunter Wu.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/msm_hsusb.h>
+
+#include "ehci-msm7201.h"
+
+#if 1
+static unsigned ulpi_read(struct usb_hcd *hcd, unsigned reg)
+{
+ unsigned timeout = 100000;
+
+ /* initiate read operation */
+ writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
+
+ if (timeout == 0) {
+ printk(KERN_ERR "ulpi_read: timeout %08x\n", readl(USB_ULPI_VIEWPORT));
+ return 0xffffffff;
+ }
+ return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+#endif
+
+static void ulpi_write(struct usb_hcd *hcd, unsigned val, unsigned reg)
+{
+ unsigned timeout = 10000;
+
+ /* initiate write operation */
+ writel(ULPI_RUN | ULPI_WRITE |
+ ULPI_ADDR(reg) | ULPI_DATA(val),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
+
+ if (timeout == 0)
+ printk(KERN_WARNING "%s: timeout: reg: 0x%X, var: 0x%X\n",
+ __func__, reg, val);
+}
+
+static void msm7201_setup_phy(struct usb_hcd *hcd)
+{
+ struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+
+ int *seq = msm7201->phy_init_seq;
+
+ if (!seq)
+ return;
+
+ while (seq[0] >= 0) {
+ ulpi_write(hcd, seq[0], seq[1]);
+ seq += 2;
+ }
+}
+
+static void msm7201_shutdown_phy(struct usb_hcd *hcd)
+{
+ struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+
+ if (msm7201->phy_shutdown)
+ msm7201->phy_shutdown();
+
+ /* disable interface protect circuit to drop current consumption */
+ ulpi_write(hcd, (1 << 7), 0x08);
+ /* clear the SuspendM bit -> suspend the PHY */
+ ulpi_write(hcd, 1 << 6, 0x06);
+}
+
+static void msm7201_usb_setup(struct usb_hcd *hcd)
+{
+ struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+ int i;
+
+ if (msm7201->phy_reset)
+ msm7201->phy_reset();
+
+ /* INCR8 BURST mode */
+ writel(0x02, USB_SBUSCFG); /*boost performance to fix CRC error.*/
+
+ /* select ULPI phy */
+ writel(0x80000000, USB_PORTSC);
+
+ msm7201_setup_phy(hcd);
+}
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int ehci_msm7201_reinit(struct ehci_hcd *ehci)
+{
+ msm7201_usb_setup(ehci_to_hcd(ehci));
+ ehci_port_power(ehci, 0);
+
+ return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int ehci_msm7201_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ /* EHCI registers start at offset 0x100 */
+ ehci->caps = hcd->regs + 0x100;
+ ehci->regs = hcd->regs + 0x100 +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* configure other settings */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ hcd->has_tt = 1;
+ ehci->sbrn = 0x20;
+
+ /* reset and halt controller */
+ ehci_reset(ehci);
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ /* data structure init */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_reset(ehci);
+
+ retval = ehci_msm7201_reinit(ehci);
+ return retval;
+}
+
+static const struct hc_driver ehci_msm7201_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Qualcomm MSM7201 On-Chip EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd) + sizeof(struct msm7201_usb_priv),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_msm7201_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+};
+
+/**
+ * usb_hcd_msm7201_remove - shutdown processing for MSM7201-based HCDs
+ * @pdev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_msm7201_probe().
+ *
+ */
+static int usb_hcd_msm7201_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+
+ usb_remove_hcd(hcd);
+ msm7201_shutdown_phy(hcd);
+ clk_put(msm7201->clk);
+ clk_put(msm7201->pclk);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+/**
+ * usb_hcd_msm7201_probe - initialize MSM7201-based HCDs
+ * @pdev: USB Host Controller being probed
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller.
+ *
+ */
+static int usb_hcd_msm7201_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ struct msm7201_usb_priv *msm7201;
+ int irq;
+ int retval;
+ const struct hc_driver *driver = &ehci_msm7201_hc_driver;
+ struct msm_hsusb_platform_data *pdata = pdev->dev.platform_data;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_debug("initializing MSM7201 USB Controller\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+ msm7201 = hcd_to_msm7201(hcd);
+ if (pdata) {
+ msm7201->phy_reset = pdata->phy_reset;
+ msm7201->phy_shutdown = pdata->phy_shutdown;
+ msm7201->phy_init_seq = pdata->phy_init_seq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ retval = -ENODEV;
+ goto err2;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto err2;
+ }
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+
+ if (hcd->regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto err3;
+ }
+
+ msm7201->clk = clk_get(&pdev->dev, "usb_hs_clk");
+ if (IS_ERR(msm7201->clk)) {
+ dev_dbg(&pdev->dev, "error getting usb_hs_clk\n");
+ retval = -EFAULT;
+ goto err4;
+ }
+
+ msm7201->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
+ if (IS_ERR(msm7201->pclk)) {
+ dev_dbg(&pdev->dev, "error getting usb_hs_pclk\n");
+ retval = -EFAULT;
+ goto err5;
+ }
+
+ clk_enable(msm7201->clk);
+ clk_enable(msm7201->pclk);
+
+ /* wait for a while after enable usb clk*/
+ msleep(5);
+
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (retval != 0)
+ goto err6;
+ return retval;
+
+ err6:
+ clk_put(msm7201->pclk);
+ err5:
+ clk_put(msm7201->clk);
+ err4:
+ iounmap(hcd->regs);
+ err3:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err2:
+ usb_put_hcd(hcd);
+ err1:
+ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
+ return retval;
+}
+
+MODULE_ALIAS("platform:msm_hsusb");
+
+static struct platform_driver ehci_msm7201_driver = {
+ .probe = usb_hcd_msm7201_probe,
+ .remove = usb_hcd_msm7201_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "msm_hsusb",
+ },
+};
--- kernel_hero/drivers/usb/host/ehci-msm7201.h 1970-01-01 01:00:00.000000000 +0100
+++ kernel_hero.patched/drivers/usb/host/ehci-msm7201.h 2010-02-01 20:29:31.270065721 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010 Andrew de Quincey
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _EHCI_MSM7201_H
+#define _EHCI_MSM7201_H
+
+struct msm7201_usb_priv
+{
+ struct clk *clk;
+ struct clk *pclk;
+
+ int *phy_init_seq;
+ void (*phy_reset)(void);
+ void (*phy_shutdown)(void);
+};
+
+static inline struct msm7201_usb_priv *hcd_to_msm7201(struct usb_hcd *hcd)
+{
+ return (struct msm7201_usb_priv *) (hcd->hcd_priv) + sizeof(struct ehci_hcd);
+}
+
+#define MSM_USB_BASE ((unsigned) hcd->regs)
+
+#define USB_ID (MSM_USB_BASE + 0x0000)
+#define USB_HWGENERAL (MSM_USB_BASE + 0x0004)
+#define USB_HWHOST (MSM_USB_BASE + 0x0008)
+#define USB_HWDEVICE (MSM_USB_BASE + 0x000C)
+#define USB_HWTXBUF (MSM_USB_BASE + 0x0010)
+#define USB_HWRXBUF (MSM_USB_BASE + 0x0014)
+#define USB_SBUSCFG (MSM_USB_BASE + 0x0090)
+
+#define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HCIVERSION (MSM_USB_BASE + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS (MSM_USB_BASE + 0x0104)
+#define USB_HCCPARAMS (MSM_USB_BASE + 0x0108)
+#define USB_DCIVERSION (MSM_USB_BASE + 0x0120) /* 16 bit */
+#define USB_USBCMD (MSM_USB_BASE + 0x0140)
+#define USB_USBSTS (MSM_USB_BASE + 0x0144)
+#define USB_USBINTR (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX (MSM_USB_BASE + 0x014C)
+#define USB_DEVICEADDR (MSM_USB_BASE + 0x0154)
+#define USB_ENDPOINTLISTADDR (MSM_USB_BASE + 0x0158)
+#define USB_BURSTSIZE (MSM_USB_BASE + 0x0160)
+#define USB_TXFILLTUNING (MSM_USB_BASE + 0x0164)
+#define USB_ULPI_VIEWPORT (MSM_USB_BASE + 0x0170)
+#define USB_ENDPTNAK (MSM_USB_BASE + 0x0178)
+#define USB_ENDPTNAKEN (MSM_USB_BASE + 0x017C)
+#define USB_PORTSC (MSM_USB_BASE + 0x0184)
+#define USB_OTGSC (MSM_USB_BASE + 0x01A4)
+#define USB_USBMODE (MSM_USB_BASE + 0x01A8)
+#define USB_ENDPTSETUPSTAT (MSM_USB_BASE + 0x01AC)
+#define USB_ENDPTPRIME (MSM_USB_BASE + 0x01B0)
+#define USB_ENDPTFLUSH (MSM_USB_BASE + 0x01B4)
+#define USB_ENDPTSTAT (MSM_USB_BASE + 0x01B8)
+#define USB_ENDPTCOMPLETE (MSM_USB_BASE + 0x01BC)
+#define USB_ENDPTCTRL(n) (MSM_USB_BASE + 0x01C0 + (4 * (n)))
+
+#define USBCMD_RESET 2
+#define USBCMD_ATTACH 1
+#define USBCMD_ATDTW (1 << 14)
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST 3
+
+#define ULPI_WAKEUP (1 << 31)
+#define ULPI_RUN (1 << 30)
+#define ULPI_WRITE (1 << 29)
+#define ULPI_READ (0 << 29)
+#define ULPI_STATE_NORMAL (1 << 27)
+#define ULPI_ADDR(n) (((n) & 255) << 16)
+#define ULPI_DATA(n) ((n) & 255)
+#define ULPI_DATA_READ(n) (((n) >> 8) & 255)
+
+#endif /* _EHCI_MSM7201_H */
--- kernel_hero/drivers/usb/host/Kconfig 2009-10-22 07:39:59.000000000 +0100
+++ kernel_hero.patched/drivers/usb/host/Kconfig 2010-02-07 18:27:17.314978017 +0000
@@ -88,6 +88,13 @@
---help---
Variation of ARC USB block used in some Freescale chips.
+config USB_EHCI_MSM7201
+ bool "Support for Qualcomm MSM7201 on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && ARCH_MSM7XXX && (!USB_FUNCTION)
+ select USB_EHCI_ROOT_HUB_TT
+ ---help---
+ Variation of ARC USB block used in Qualcomm MSM7201 chips.
+
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
depends on USB_EHCI_HCD && PPC_OF