diff --git a/board/genesi/mx51_efikamx/efikamx-usb.c b/board/genesi/mx51_efikamx/efikamx-usb.c
index 0c0b8d31818baced625539a8a55f765403532ec9..9dfd24961af03a05e5be55d7563f012b0a3f55cc 100644
--- a/board/genesi/mx51_efikamx/efikamx-usb.c
+++ b/board/genesi/mx51_efikamx/efikamx-usb.c
@@ -173,8 +173,9 @@ int board_ehci_hcd_init(int port)
 	return 0;
 }
 
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
-			uint32_t *reg)
+/* This overrides a weak function */
+void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			   uint32_t *reg)
 {
 	uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT);
 	struct usb_ehci *ehci = (struct usb_ehci *)port;
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
index b865fea3eba7c54449db8ab212dbf2c5829515f9..821222cc5d7c3fe3d2f3f3ab671163eb22aba066 100644
--- a/drivers/usb/host/ehci-faraday.c
+++ b/drivers/usb/host/ehci-faraday.c
@@ -29,6 +29,59 @@ static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
 	return !readl(&regs->usb.easstr);
 }
 
+void faraday_ehci_set_usbmode(struct ehci_ctrl *ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int faraday_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+{
+	int spd, ret = PORTSC_PSPD_HS;
+	union ehci_faraday_regs *regs;
+
+	ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		ret = PORTSC_PSPD_FS;
+		break;
+	case 1:    /* low  speed */
+		ret = PORTSC_PSPD_LS;
+		break;
+	case 2:    /* high speed */
+		ret = PORTSC_PSPD_HS;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+uint32_t *faraday_ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port) {
+		/* Printing the message would cause a scan failure! */
+		debug("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
+}
+
+static const struct ehci_ops faraday_ehci_ops = {
+	.set_usb_mode		= faraday_ehci_set_usbmode,
+	.get_port_speed		= faraday_ehci_get_port_speed,
+	.get_portsc_register	= faraday_ehci_get_portsc_register,
+};
+
 /*
  * Create the appropriate control structures to manage
  * a new EHCI host controller.
@@ -43,6 +96,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 
 	if (index < 0 || index >= ARRAY_SIZE(base_list))
 		return -1;
+	ehci_set_controller_priv(index, NULL, &faraday_ehci_ops);
 	regs = (void __iomem *)base_list[index];
 	hccr = (struct ehci_hccr *)&regs->usb.hccr;
 	hcor = (struct ehci_hcor *)&regs->usb.hcor;
@@ -87,62 +141,3 @@ int ehci_hcd_stop(int index)
 {
 	return 0;
 }
-
-/*
- * This ehci_set_usbmode() overrides the weak function
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(struct ehci_ctrl *ctrl)
-{
-	/* nothing needs to be done */
-}
-
-/*
- * This ehci_get_port_speed() overrides the weak function
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
-{
-	int spd, ret = PORTSC_PSPD_HS;
-	union ehci_faraday_regs *regs;
-
-	ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
-	if (ehci_is_fotg2xx(regs))
-		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
-	else
-		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
-
-	switch (spd) {
-	case 0:    /* full speed */
-		ret = PORTSC_PSPD_FS;
-		break;
-	case 1:    /* low  speed */
-		ret = PORTSC_PSPD_LS;
-		break;
-	case 2:    /* high speed */
-		ret = PORTSC_PSPD_HS;
-		break;
-	default:
-		printf("ehci-faraday: invalid device speed\n");
-		break;
-	}
-
-	return ret;
-}
-
-/*
- * This ehci_get_portsc_register() overrides the weak function
- * in "ehci-hcd.c".
- */
-uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
-{
-	/* Faraday EHCI has one and only one portsc register */
-	if (port) {
-		/* Printing the message would cause a scan failure! */
-		debug("The request port(%d) is not configured\n", port);
-		return NULL;
-	}
-
-	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
-	return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
-}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9a9ec01d9f6bf4dc52eda7034be3d8ae41aef4ff..c6696aab5067d82f9f4a9043c62f8923fea2283a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -124,12 +124,12 @@ static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
 	return udev->controller;
 }
 
-__weak int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+static int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	return PORTSC_PSPD(reg);
 }
 
-__weak void ehci_set_usbmode(struct ehci_ctrl *ctrl)
+static void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 {
 	uint32_t tmp;
 	uint32_t *reg_ptr;
@@ -143,13 +143,13 @@ __weak void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 	ehci_writel(reg_ptr, tmp);
 }
 
-__weak void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 			       uint32_t *reg)
 {
 	mdelay(50);
 }
 
-__weak uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
 {
 	if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
 		/* Printing the message would cause a scan failure! */
@@ -178,6 +178,7 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 
 static int ehci_reset(int index)
 {
+	struct ehci_ctrl *ctrl = &ehcic[index];
 	uint32_t cmd;
 	int ret = 0;
 
@@ -192,7 +193,7 @@ static int ehci_reset(int index)
 	}
 
 	if (ehci_is_TDI())
-		ehci_set_usbmode(&ehcic[index]);
+		ctrl->ops.set_usb_mode(&ehcic[index]);
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -691,7 +692,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
 	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
 	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
 	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
-		status_reg = ehci_get_portsc_register(ctrl, port - 1);
+		status_reg = ctrl->ops.get_portsc_register(ctrl, port - 1);
 		if (!status_reg)
 			return -1;
 		break;
@@ -786,7 +787,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
-			switch (ehci_get_port_speed(ctrl, reg)) {
+			switch (ctrl->ops.get_port_speed(ctrl, reg)) {
 			case PORTSC_PSPD_FS:
 				break;
 			case PORTSC_PSPD_LS:
@@ -848,7 +849,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
 				 * usb 2.0 specification say 50 ms resets on
 				 * root
 				 */
-				ehci_powerup_fixup(ctrl, status_reg, &reg);
+				ctrl->ops.powerup_fixup(ctrl, status_reg, &reg);
 
 				ehci_writel(status_reg, reg & ~EHCI_PS_PR);
 				/*
@@ -935,9 +936,37 @@ unknown:
 	return -1;
 }
 
-void ehci_set_controller_priv(int index, void *priv)
+const struct ehci_ops default_ehci_ops = {
+	.set_usb_mode		= ehci_set_usbmode,
+	.get_port_speed		= ehci_get_port_speed,
+	.powerup_fixup		= ehci_powerup_fixup,
+	.get_portsc_register	= ehci_get_portsc_register,
+};
+
+static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops)
+{
+	if (!ops) {
+		ctrl->ops = default_ehci_ops;
+	} else {
+		ctrl->ops = *ops;
+		if (!ctrl->ops.set_usb_mode)
+			ctrl->ops.set_usb_mode = ehci_set_usbmode;
+		if (!ctrl->ops.get_port_speed)
+			ctrl->ops.get_port_speed = ehci_get_port_speed;
+		if (!ctrl->ops.powerup_fixup)
+			ctrl->ops.powerup_fixup = ehci_powerup_fixup;
+		if (!ctrl->ops.get_portsc_register)
+			ctrl->ops.get_portsc_register =
+					ehci_get_portsc_register;
+	}
+}
+
+void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops)
 {
-	ehcic[index].priv = priv;
+	struct ehci_ctrl *ctrl = &ehcic[index];
+
+	ctrl->priv = priv;
+	ehci_setup_ops(ctrl, ops);
 }
 
 void *ehci_get_controller_priv(int index)
@@ -1066,6 +1095,12 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	uint tweaks = 0;
 	int rc;
 
+	/**
+	 * Set ops to default_ehci_ops, ehci_hcd_init should call
+	 * ehci_set_controller_priv to change any of these function pointers.
+	 */
+	ctrl->ops = default_ehci_ops;
+
 	rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
 	if (rc)
 		return rc;
diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c
index 7566c61284eb2c29d2a0fc1cc423e4fd219570f1..d3199622eb948695db092f997c0021387271107f 100644
--- a/drivers/usb/host/ehci-mx5.c
+++ b/drivers/usb/host/ehci-mx5.c
@@ -218,11 +218,23 @@ void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
 {
 }
 
+__weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+				   uint32_t *reg)
+{
+	mdelay(50);
+}
+
+static const struct ehci_ops mx5_ehci_ops = {
+	.powerup_fixup		= mx5_ehci_powerup_fixup,
+};
+
 int ehci_hcd_init(int index, enum usb_init_type init,
 		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
 {
 	struct usb_ehci *ehci;
 
+	/* The only user for this is efikamx-usb */
+	ehci_set_controller_priv(index, NULL, &mx5_ehci_ops);
 	set_usboh3_clk();
 	enable_usboh3_clk(true);
 	set_usb_phy_clk();
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 0e6b60e0d6a88c9fe74a708d8a08901c5338fd84..9e380c309eeba080c29f89775a7aa34eb602d750 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -193,11 +193,9 @@ static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
  * A known hardware issue where Connect Status Change bit of PORTSC register
  * of USB1 controller will be set after Port Reset.
  * We have to clear it in order for later device enumeration to proceed.
- * This ehci_powerup_fixup overrides the weak function ehci_powerup_fixup
- * in "ehci-hcd.c".
  */
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
-			uint32_t *reg)
+static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
+				     uint32_t *status_reg, uint32_t *reg)
 {
 	struct fdt_usb *config = ctrl->priv;
 	struct fdt_usb_controller *controller;
@@ -215,11 +213,7 @@ void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 		*reg |= EHCI_PS_CSC;
 }
 
-/*
- * This ehci_set_usbmode overrides the weak function ehci_set_usbmode
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(struct ehci_ctrl *ctrl)
+static void tegra_ehci_set_usbmode(struct ehci_ctrl *ctrl)
 {
 	struct fdt_usb *config = ctrl->priv;
 	struct usb_ctlr *usbctlr;
@@ -232,11 +226,7 @@ void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 	ehci_writel(&usbctlr->usb_mode, tmp);
 }
 
-/*
- * This ehci_get_port_speed overrides the weak function ehci_get_port_speed
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+static int tegra_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	struct fdt_usb *config = ctrl->priv;
 	struct fdt_usb_controller *controller;
@@ -714,6 +704,12 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	return 0;
 }
 
+static const struct ehci_ops tegra_ehci_ops = {
+	.set_usb_mode		= tegra_ehci_set_usbmode,
+	.get_port_speed		= tegra_ehci_get_port_speed,
+	.powerup_fixup		= tegra_ehci_powerup_fixup,
+};
+
 /*
  * process_usb_nodes() - Process a list of USB nodes, adding them to our list
  *			of USB ports.
@@ -805,7 +801,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 		return -1;
 
 	config = &port[index];
-	ehci_set_controller_priv(index, config);
+	ehci_set_controller_priv(index, config, &tegra_ehci_ops);
 
 	switch (init) {
 	case USB_INIT_HOST:
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2ca111a3002d20639946bb71b1890d3565413001..cc23e1fe93f34422968832f25bac2c6012f2324a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -244,6 +244,16 @@ enum {
 	EHCI_TWEAK_NO_INIT_CF		= 1 << 0,
 };
 
+struct ehci_ctrl;
+
+struct ehci_ops {
+	void (*set_usb_mode)(struct ehci_ctrl *ctrl);
+	int (*get_port_speed)(struct ehci_ctrl *ctrl, uint32_t reg);
+	void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			      uint32_t *reg);
+	uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port);
+};
+
 struct ehci_ctrl {
 	struct ehci_hccr *hccr;	/* R/O registers, not need for volatile */
 	struct ehci_hcor *hcor;
@@ -254,27 +264,24 @@ struct ehci_ctrl {
 	uint32_t *periodic_list;
 	int periodic_schedules;
 	int ntds;
+	struct ehci_ops ops;
 	void *priv;	/* client's private data */
 };
 
-/* Weak functions that drivers can override */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
-void ehci_set_usbmode(struct ehci_ctrl *ctrl);
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
-			uint32_t *reg);
-uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port);
-
 /**
- * ehci_set_controller_priv() - Set up private data for the controller
+ * ehci_set_controller_info() - Set up private data for the controller
  *
  * This function can be called in ehci_hcd_init() to tell the EHCI layer
  * about the controller's private data pointer. Then in the above functions
- * this can be accessed given the struct ehci_ctrl pointer.
+ * this can be accessed given the struct ehci_ctrl pointer. Also special
+ * EHCI operation methods can be provided if required
  *
  * @index:	Controller number to set
  * @priv:	Controller pointer
+ * @ops:	Controller operations, or NULL to use default
  */
-void ehci_set_controller_priv(int index, void *priv);
+void ehci_set_controller_priv(int index, void *priv,
+			      const struct ehci_ops *ops);
 
 /**
  * ehci_get_controller_priv() - Get controller private data