Hi, here's my now working patch - I've still a bit of work to do on it
obviously, but it should suffice as a proof of concept
--
unsubscribe: android-kernel+unsubscr...@googlegroups.com
website: http://groups.google.com/group/android-kernel
--- 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-09 20:06:33.162966732 +0000
@@ -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-09 20:09:10.556297861 +0000
@@ -0,0 +1,319 @@
+/*
+ * 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 <rvin...@mvista.com> using code provided
+ * by Hunter Wu.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/msm_hsusb.h>
+
+#include "ehci-msm7201.h"
+
+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;
+
+ /* INCR8 BURST mode */
+ writel(0x02, USB_SBUSCFG); /*boost performance to fix CRC error.*/
+
+ /* select ULPI phy */
+ writel(0x80000000, USB_PORTSC);
+
+ if (msm7201->phy_reset)
+ msm7201->phy_reset();
+ 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 | HCD_MEMORY | HCD_LOCAL_MEM,
+
+ /*
+ * 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-09 18:22:32.530257554 +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