summary refs log tree commit diff
path: root/drivers/usb/phy
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-24 16:18:40 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-24 16:18:40 +0100
commit5328f35b1584a9849ffe46afa42018946aa43851 (patch)
treef939d0577ae13ed22069ac4188ce21bacc7a3af5 /drivers/usb/phy
parente3967e7b28de70d28313cc93d831d8525083097f (diff)
parent80d7d8a768cda6e8a08ab805a977d08741011da1 (diff)
downloadlinux-5328f35b1584a9849ffe46afa42018946aa43851.tar.gz
Merge tag 'usb-for-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:

usb: patches for v3.13

Final conversions to configfs for mass storage, acm_ms, and
multi gadgets.

MUSB should now work out of the box on AM335x-based boards
(beagle bone white and black) with DMA thanks to Sebastian's
work.

We can now enable VERBOSE_DEBUG on builds of drivers/usb/gadget/
by selecting CONFIG_USB_GADGET_VERBOSE.

s3c-hsotg got quite a few non-critical fixes but also learned
a few new tricks (isochronous transfers, multi count support).

The Marvel USB3 Controller driver got a memory leak fix.

devm_usb_get_phy() learned not to return NULL, ever.

Other than these patches, we have the usual set of cleanups
ranging from removal of unnecessary *_set_drvdata() to using
SIMPLE_DEV_PM_OPS.

Signed-of-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy')
-rw-r--r--drivers/usb/phy/Kconfig13
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/phy-am335x-control.c44
-rw-r--r--drivers/usb/phy/phy-am335x.c44
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c96
-rw-r--r--drivers/usb/phy/phy-fsl-usb.h4
-rw-r--r--drivers/usb/phy/phy-fsm-usb.c72
-rw-r--r--drivers/usb/phy/phy-fsm-usb.h179
-rw-r--r--drivers/usb/phy/phy-generic.c108
-rw-r--r--drivers/usb/phy/phy-generic.h7
-rw-r--r--drivers/usb/phy/phy-rcar-gen2-usb.c248
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c2
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c1
-rw-r--r--drivers/usb/phy/phy.c2
14 files changed, 666 insertions, 155 deletions
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 64b8bef1919e..08e2f39027ec 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -194,6 +194,19 @@ config USB_RCAR_PHY
 	  To compile this driver as a module, choose M here: the
 	  module will be called phy-rcar-usb.
 
+config USB_RCAR_GEN2_PHY
+	tristate "Renesas R-Car Gen2 USB PHY support"
+	depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
+	select USB_PHY
+	help
+	  Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver.
+	  It is typically used to control internal USB PHY for USBHS,
+	  and to configure shared USB channels 0 and 2.
+	  This driver supports R8A7790 and R8A7791.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called phy-rcar-gen2-usb.
+
 config USB_ULPI
 	bool "Generic ULPI Transceiver Driver"
 	depends on ARM
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 9c3736109c2c..022c1da7fb78 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -27,5 +27,6 @@ obj-$(CONFIG_USB_MSM_OTG)		+= phy-msm-usb.o
 obj-$(CONFIG_USB_MV_OTG)		+= phy-mv-usb.o
 obj-$(CONFIG_USB_MXS_PHY)		+= phy-mxs-usb.o
 obj-$(CONFIG_USB_RCAR_PHY)		+= phy-rcar-usb.o
+obj-$(CONFIG_USB_RCAR_GEN2_PHY)		+= phy-rcar-gen2-usb.o
 obj-$(CONFIG_USB_ULPI)			+= phy-ulpi.o
 obj-$(CONFIG_USB_ULPI_VIEWPORT)		+= phy-ulpi-viewport.o
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
index 22cf07d62e4c..634f49acd20e 100644
--- a/drivers/usb/phy/phy-am335x-control.c
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -26,6 +26,41 @@ struct am335x_control_usb {
 #define USBPHY_OTGVDET_EN	(1 << 19)
 #define USBPHY_OTGSESSEND_EN	(1 << 20)
 
+#define AM335X_PHY0_WK_EN	(1 << 0)
+#define AM335X_PHY1_WK_EN	(1 << 8)
+
+static void am335x_phy_wkup(struct  phy_control *phy_ctrl, u32 id, bool on)
+{
+	struct am335x_control_usb *usb_ctrl;
+	u32 val;
+	u32 reg;
+
+	usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
+
+	switch (id) {
+	case 0:
+		reg = AM335X_PHY0_WK_EN;
+		break;
+	case 1:
+		reg = AM335X_PHY1_WK_EN;
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+
+	spin_lock(&usb_ctrl->lock);
+	val = readl(usb_ctrl->wkup);
+
+	if (on)
+		val |= reg;
+	else
+		val &= ~reg;
+
+	writel(val, usb_ctrl->wkup);
+	spin_unlock(&usb_ctrl->lock);
+}
+
 static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
 {
 	struct am335x_control_usb *usb_ctrl;
@@ -59,6 +94,7 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
 
 static const struct phy_control ctrl_am335x = {
 	.phy_power = am335x_phy_power,
+	.phy_wkup = am335x_phy_wkup,
 };
 
 static const struct of_device_id omap_control_usb_id_table[] = {
@@ -117,6 +153,12 @@ static int am335x_control_usb_probe(struct platform_device *pdev)
 	ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(ctrl_usb->phy_reg))
 		return PTR_ERR(ctrl_usb->phy_reg);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wakeup");
+	ctrl_usb->wkup = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctrl_usb->wkup))
+		return PTR_ERR(ctrl_usb->wkup);
+
 	spin_lock_init(&ctrl_usb->lock);
 	ctrl_usb->phy_ctrl = *phy_ctrl;
 
@@ -129,7 +171,7 @@ static struct platform_driver am335x_control_driver = {
 	.driver		= {
 		.name	= "am335x-control-usb",
 		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(omap_control_usb_id_table),
+		.of_match_table = omap_control_usb_id_table,
 	},
 };
 
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index c4d614d1f173..6370e50649d7 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -53,21 +53,20 @@ static int am335x_phy_probe(struct platform_device *pdev)
 	}
 
 	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen,
-			USB_PHY_TYPE_USB2, 0, false, false);
+			USB_PHY_TYPE_USB2, 0, false);
 	if (ret)
 		return ret;
 
 	ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
 	if (ret)
-		goto err_add;
+		return ret;
 	am_phy->usb_phy_gen.phy.init = am335x_init;
 	am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
 
 	platform_set_drvdata(pdev, am_phy);
+
 	return 0;
 
-err_add:
-	usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen);
 	return ret;
 }
 
@@ -79,6 +78,40 @@ static int am335x_phy_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+
+static int am335x_phy_runtime_suspend(struct device *dev)
+{
+	struct platform_device	*pdev = to_platform_device(dev);
+	struct am335x_phy *am_phy = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(dev))
+		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true);
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+	return 0;
+}
+
+static int am335x_phy_runtime_resume(struct device *dev)
+{
+	struct platform_device	*pdev = to_platform_device(dev);
+	struct am335x_phy	*am_phy = platform_get_drvdata(pdev);
+
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+	if (device_may_wakeup(dev))
+		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false);
+	return 0;
+}
+
+static const struct dev_pm_ops am335x_pm_ops = {
+	SET_RUNTIME_PM_OPS(am335x_phy_runtime_suspend,
+			am335x_phy_runtime_resume, NULL)
+};
+
+#define DEV_PM_OPS	(&am335x_pm_ops)
+#else
+#define DEV_PM_OPS	NULL
+#endif
+
 static const struct of_device_id am335x_phy_ids[] = {
 	{ .compatible = "ti,am335x-usb-phy" },
 	{ }
@@ -91,7 +124,8 @@ static struct platform_driver am335x_phy_driver = {
 	.driver         = {
 		.name   = "am335x-phy-driver",
 		.owner  = THIS_MODULE,
-		.of_match_table = of_match_ptr(am335x_phy_ids),
+		.pm = DEV_PM_OPS,
+		.of_match_table = am335x_phy_ids,
 	},
 };
 
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index fa7c9f9628b5..7f3c73b967ce 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -134,7 +134,7 @@ int write_ulpi(u8 addr, u8 data)
 /* Operations that will be called from OTG Finite State Machine */
 
 /* Charge vbus for vbus pulsing in SRP */
-void fsl_otg_chrg_vbus(int on)
+void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -170,7 +170,7 @@ void fsl_otg_dischrg_vbus(int on)
 }
 
 /* A-device driver vbus, controlled through PP bit in PORTSC */
-void fsl_otg_drv_vbus(int on)
+void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -188,7 +188,7 @@ void fsl_otg_drv_vbus(int on)
  * Pull-up D+, signalling connect by periperal. Also used in
  * data-line pulsing in SRP
  */
-void fsl_otg_loc_conn(int on)
+void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -207,7 +207,7 @@ void fsl_otg_loc_conn(int on)
  * port.  In host mode, controller will automatically send SOF.
  * Suspend will block the data on the port.
  */
-void fsl_otg_loc_sof(int on)
+void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
 {
 	u32 tmp;
 
@@ -222,7 +222,7 @@ void fsl_otg_loc_sof(int on)
 }
 
 /* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
-void fsl_otg_start_pulse(void)
+void fsl_otg_start_pulse(struct otg_fsm *fsm)
 {
 	u32 tmp;
 
@@ -235,7 +235,7 @@ void fsl_otg_start_pulse(void)
 	fsl_otg_loc_conn(1);
 #endif
 
-	fsl_otg_add_timer(b_data_pulse_tmr);
+	fsl_otg_add_timer(fsm, b_data_pulse_tmr);
 }
 
 void b_data_pulse_end(unsigned long foo)
@@ -252,14 +252,14 @@ void b_data_pulse_end(unsigned long foo)
 void fsl_otg_pulse_vbus(void)
 {
 	srp_wait_done = 0;
-	fsl_otg_chrg_vbus(1);
+	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 1);
 	/* start the timer to end vbus charge */
-	fsl_otg_add_timer(b_vbus_pulse_tmr);
+	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_vbus_pulse_tmr);
 }
 
 void b_vbus_pulse_end(unsigned long foo)
 {
-	fsl_otg_chrg_vbus(0);
+	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 0);
 
 	/*
 	 * As USB3300 using the same a_sess_vld and b_sess_vld voltage
@@ -267,7 +267,7 @@ void b_vbus_pulse_end(unsigned long foo)
 	 * residual voltage of vbus pulsing and A device pull up
 	 */
 	fsl_otg_dischrg_vbus(1);
-	fsl_otg_add_timer(b_srp_wait_tmr);
+	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_srp_wait_tmr);
 }
 
 void b_srp_end(unsigned long foo)
@@ -289,7 +289,7 @@ void a_wait_enum(unsigned long foo)
 {
 	VDBG("a_wait_enum timeout\n");
 	if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
-		fsl_otg_add_timer(a_wait_enum_tmr);
+		fsl_otg_add_timer(&fsl_otg_dev->fsm, a_wait_enum_tmr);
 	else
 		otg_statemachine(&fsl_otg_dev->fsm);
 }
@@ -375,8 +375,42 @@ void fsl_otg_uninit_timers(void)
 	kfree(b_vbus_pulse_tmr);
 }
 
+static struct fsl_otg_timer *fsl_otg_get_timer(enum otg_fsm_timer t)
+{
+	struct fsl_otg_timer *timer;
+
+	/* REVISIT: use array of pointers to timers instead */
+	switch (t) {
+	case A_WAIT_VRISE:
+		timer = a_wait_vrise_tmr;
+		break;
+	case A_WAIT_BCON:
+		timer = a_wait_vrise_tmr;
+		break;
+	case A_AIDL_BDIS:
+		timer = a_wait_vrise_tmr;
+		break;
+	case B_ASE0_BRST:
+		timer = a_wait_vrise_tmr;
+		break;
+	case B_SE0_SRP:
+		timer = a_wait_vrise_tmr;
+		break;
+	case B_SRP_FAIL:
+		timer = a_wait_vrise_tmr;
+		break;
+	case A_WAIT_ENUM:
+		timer = a_wait_vrise_tmr;
+		break;
+	default:
+		timer = NULL;
+	}
+
+	return timer;
+}
+
 /* Add timer to timer list */
-void fsl_otg_add_timer(void *gtimer)
+void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer)
 {
 	struct fsl_otg_timer *timer = gtimer;
 	struct fsl_otg_timer *tmp_timer;
@@ -394,8 +428,19 @@ void fsl_otg_add_timer(void *gtimer)
 	list_add_tail(&timer->list, &active_timers);
 }
 
+static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+{
+	struct fsl_otg_timer *timer;
+
+	timer = fsl_otg_get_timer(t);
+	if (!timer)
+		return;
+
+	fsl_otg_add_timer(fsm, timer);
+}
+
 /* Remove timer from the timer list; clear timeout status */
-void fsl_otg_del_timer(void *gtimer)
+void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer)
 {
 	struct fsl_otg_timer *timer = gtimer;
 	struct fsl_otg_timer *tmp_timer, *del_tmp;
@@ -405,6 +450,17 @@ void fsl_otg_del_timer(void *gtimer)
 			list_del(&timer->list);
 }
 
+static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+{
+	struct fsl_otg_timer *timer;
+
+	timer = fsl_otg_get_timer(t);
+	if (!timer)
+		return;
+
+	fsl_otg_del_timer(fsm, timer);
+}
+
 /*
  * Reduce timer count by 1, and find timeout conditions.
  * Called by fsl_otg 1ms timer interrupt
@@ -468,7 +524,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 				retval = dev->driver->pm->resume(dev);
 				if (fsm->id) {
 					/* default-b */
-					fsl_otg_drv_vbus(1);
+					fsl_otg_drv_vbus(fsm, 1);
 					/*
 					 * Workaround: b_host can't driver
 					 * vbus, but PP in PORTSC needs to
@@ -493,7 +549,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 					retval = dev->driver->pm->suspend(dev);
 				if (fsm->id)
 					/* default-b */
-					fsl_otg_drv_vbus(0);
+					fsl_otg_drv_vbus(fsm, 0);
 			}
 			otg_dev->host_working = 0;
 		}
@@ -757,8 +813,8 @@ static struct otg_fsm_ops fsl_otg_ops = {
 	.loc_sof = fsl_otg_loc_sof,
 	.start_pulse = fsl_otg_start_pulse,
 
-	.add_timer = fsl_otg_add_timer,
-	.del_timer = fsl_otg_del_timer,
+	.add_timer = fsl_otg_fsm_add_timer,
+	.del_timer = fsl_otg_fsm_del_timer,
 
 	.start_host = fsl_otg_start_host,
 	.start_gadget = fsl_otg_start_gadget,
@@ -1011,7 +1067,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
 			"b_bus_suspend: %d\n"
 			"b_conn: %d\n"
 			"b_se0_srp: %d\n"
-			"b_sess_end: %d\n"
+			"b_ssend_srp: %d\n"
 			"b_sess_vld: %d\n"
 			"id: %d\n",
 			fsm->a_bus_req,
@@ -1026,7 +1082,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
 			fsm->b_bus_suspend,
 			fsm->b_conn,
 			fsm->b_se0_srp,
-			fsm->b_sess_end,
+			fsm->b_ssend_srp,
 			fsm->b_sess_vld,
 			fsm->id);
 	size -= t;
@@ -1057,7 +1113,7 @@ static long fsl_otg_ioctl(struct file *file, unsigned int cmd,
 		break;
 
 	case SET_A_SUSPEND_REQ:
-		fsl_otg_dev->fsm.a_suspend_req = arg;
+		fsl_otg_dev->fsm.a_suspend_req_inf = arg;
 		break;
 
 	case SET_A_BUS_DROP:
diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
index e1859b8ef567..7365170a2f23 100644
--- a/drivers/usb/phy/phy-fsl-usb.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
@@ -401,6 +401,6 @@ struct fsl_otg_config {
 #define GET_A_BUS_REQ		_IOR(OTG_IOCTL_MAGIC, 8, int)
 #define GET_B_BUS_REQ		_IOR(OTG_IOCTL_MAGIC, 9, int)
 
-void fsl_otg_add_timer(void *timer);
-void fsl_otg_del_timer(void *timer);
+void fsl_otg_add_timer(struct otg_fsm *fsm, void *timer);
+void fsl_otg_del_timer(struct otg_fsm *fsm, void *timer);
 void fsl_otg_pulse_vbus(void);
diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c
index 7f4596606e18..329c2d2f8595 100644
--- a/drivers/usb/phy/phy-fsm-usb.c
+++ b/drivers/usb/phy/phy-fsm-usb.c
@@ -41,17 +41,17 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 			fsm->protocol, protocol);
 		/* stop old protocol */
 		if (fsm->protocol == PROTO_HOST)
-			ret = fsm->ops->start_host(fsm, 0);
+			ret = otg_start_host(fsm, 0);
 		else if (fsm->protocol == PROTO_GADGET)
-			ret = fsm->ops->start_gadget(fsm, 0);
+			ret = otg_start_gadget(fsm, 0);
 		if (ret)
 			return ret;
 
 		/* start new protocol */
 		if (protocol == PROTO_HOST)
-			ret = fsm->ops->start_host(fsm, 1);
+			ret = otg_start_host(fsm, 1);
 		else if (protocol == PROTO_GADGET)
-			ret = fsm->ops->start_gadget(fsm, 1);
+			ret = otg_start_gadget(fsm, 1);
 		if (ret)
 			return ret;
 
@@ -69,42 +69,50 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 {
 	switch (old_state) {
 	case OTG_STATE_B_IDLE:
-		otg_del_timer(fsm, b_se0_srp_tmr);
+		otg_del_timer(fsm, B_SE0_SRP);
 		fsm->b_se0_srp = 0;
+		fsm->adp_sns = 0;
+		fsm->adp_prb = 0;
 		break;
 	case OTG_STATE_B_SRP_INIT:
+		fsm->data_pulse = 0;
 		fsm->b_srp_done = 0;
 		break;
 	case OTG_STATE_B_PERIPHERAL:
 		break;
 	case OTG_STATE_B_WAIT_ACON:
-		otg_del_timer(fsm, b_ase0_brst_tmr);
+		otg_del_timer(fsm, B_ASE0_BRST);
 		fsm->b_ase0_brst_tmout = 0;
 		break;
 	case OTG_STATE_B_HOST:
 		break;
 	case OTG_STATE_A_IDLE:
+		fsm->adp_prb = 0;
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
-		otg_del_timer(fsm, a_wait_vrise_tmr);
+		otg_del_timer(fsm, A_WAIT_VRISE);
 		fsm->a_wait_vrise_tmout = 0;
 		break;
 	case OTG_STATE_A_WAIT_BCON:
-		otg_del_timer(fsm, a_wait_bcon_tmr);
+		otg_del_timer(fsm, A_WAIT_BCON);
 		fsm->a_wait_bcon_tmout = 0;
 		break;
 	case OTG_STATE_A_HOST:
-		otg_del_timer(fsm, a_wait_enum_tmr);
+		otg_del_timer(fsm, A_WAIT_ENUM);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		otg_del_timer(fsm, a_aidl_bdis_tmr);
+		otg_del_timer(fsm, A_AIDL_BDIS);
 		fsm->a_aidl_bdis_tmout = 0;
-		fsm->a_suspend_req = 0;
+		fsm->a_suspend_req_inf = 0;
 		break;
 	case OTG_STATE_A_PERIPHERAL:
+		otg_del_timer(fsm, A_BIDL_ADIS);
+		fsm->a_bidl_adis_tmout = 0;
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
-		otg_del_timer(fsm, a_wait_vrise_tmr);
+		otg_del_timer(fsm, A_WAIT_VFALL);
+		fsm->a_wait_vfall_tmout = 0;
+		otg_del_timer(fsm, A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
 		break;
@@ -127,14 +135,19 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_chrg_vbus(fsm, 0);
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
+		/*
+		 * Driver is responsible for starting ADP probing
+		 * if ADP sensing times out.
+		 */
+		otg_start_adp_sns(fsm);
 		otg_set_protocol(fsm, PROTO_UNDEF);
-		otg_add_timer(fsm, b_se0_srp_tmr);
+		otg_add_timer(fsm, B_SE0_SRP);
 		break;
 	case OTG_STATE_B_SRP_INIT:
 		otg_start_pulse(fsm);
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_UNDEF);
-		otg_add_timer(fsm, b_srp_fail_tmr);
+		otg_add_timer(fsm, B_SRP_FAIL);
 		break;
 	case OTG_STATE_B_PERIPHERAL:
 		otg_chrg_vbus(fsm, 0);
@@ -147,7 +160,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, b_ase0_brst_tmr);
+		otg_add_timer(fsm, B_ASE0_BRST);
 		fsm->a_bus_suspend = 0;
 		break;
 	case OTG_STATE_B_HOST:
@@ -163,6 +176,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_chrg_vbus(fsm, 0);
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
+		otg_start_adp_prb(fsm);
 		otg_set_protocol(fsm, PROTO_HOST);
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
@@ -170,14 +184,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, a_wait_vrise_tmr);
+		otg_add_timer(fsm, A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_WAIT_BCON:
 		otg_drv_vbus(fsm, 1);
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, a_wait_bcon_tmr);
+		otg_add_timer(fsm, A_WAIT_BCON);
 		break;
 	case OTG_STATE_A_HOST:
 		otg_drv_vbus(fsm, 1);
@@ -188,15 +202,15 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		 * When HNP is triggered while a_bus_req = 0, a_host will
 		 * suspend too fast to complete a_set_b_hnp_en
 		 */
-		if (!fsm->a_bus_req || fsm->a_suspend_req)
-			otg_add_timer(fsm, a_wait_enum_tmr);
+		if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
+			otg_add_timer(fsm, A_WAIT_ENUM);
 		break;
 	case OTG_STATE_A_SUSPEND:
 		otg_drv_vbus(fsm, 1);
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, a_aidl_bdis_tmr);
+		otg_add_timer(fsm, A_AIDL_BDIS);
 
 		break;
 	case OTG_STATE_A_PERIPHERAL:
@@ -204,12 +218,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_GADGET);
 		otg_drv_vbus(fsm, 1);
+		otg_add_timer(fsm, A_BIDL_ADIS);
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
 		otg_drv_vbus(fsm, 0);
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
+		otg_add_timer(fsm, A_WAIT_VFALL);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
 		otg_drv_vbus(fsm, 0);
@@ -250,7 +266,8 @@ int otg_statemachine(struct otg_fsm *fsm)
 			otg_set_state(fsm, OTG_STATE_A_IDLE);
 		else if (fsm->b_sess_vld && fsm->otg->gadget)
 			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
-		else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp)
+		else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) &&
+				fsm->b_ssend_srp && fsm->b_se0_srp)
 			otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
 		break;
 	case OTG_STATE_B_SRP_INIT:
@@ -277,13 +294,14 @@ int otg_statemachine(struct otg_fsm *fsm)
 	case OTG_STATE_B_HOST:
 		if (!fsm->id || !fsm->b_sess_vld)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
-		else if (!fsm->b_bus_req || !fsm->a_conn)
+		else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device)
 			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
 		break;
 	case OTG_STATE_A_IDLE:
 		if (fsm->id)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
-		else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det))
+		else if (!fsm->a_bus_drop && (fsm->a_bus_req ||
+			  fsm->a_srp_det || fsm->adp_change || fsm->power_up))
 			otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
@@ -301,7 +319,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
 		break;
 	case OTG_STATE_A_HOST:
-		if ((!fsm->a_bus_req || fsm->a_suspend_req) &&
+		if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
 				fsm->otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_SUSPEND);
 		else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop)
@@ -324,14 +342,14 @@ int otg_statemachine(struct otg_fsm *fsm)
 	case OTG_STATE_A_PERIPHERAL:
 		if (fsm->id || fsm->a_bus_drop)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
-		else if (fsm->b_bus_suspend)
+		else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
 		else if (!fsm->a_vbus_vld)
 			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
-		if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld &&
-					!fsm->b_conn))
+		if (fsm->a_wait_vfall_tmout || fsm->id || fsm->a_bus_req ||
+				(!fsm->a_sess_vld && !fsm->b_conn))
 			otg_set_state(fsm, OTG_STATE_A_IDLE);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h
index fbe586206f33..7441b46a27f1 100644
--- a/drivers/usb/phy/phy-fsm-usb.h
+++ b/drivers/usb/phy/phy-fsm-usb.h
@@ -34,45 +34,76 @@
 #define PROTO_HOST	(1)
 #define PROTO_GADGET	(2)
 
+enum otg_fsm_timer {
+	/* Standard OTG timers */
+	A_WAIT_VRISE,
+	A_WAIT_VFALL,
+	A_WAIT_BCON,
+	A_AIDL_BDIS,
+	B_ASE0_BRST,
+	A_BIDL_ADIS,
+
+	/* Auxiliary timers */
+	B_SE0_SRP,
+	B_SRP_FAIL,
+	A_WAIT_ENUM,
+
+	NUM_OTG_FSM_TIMERS,
+};
+
 /* OTG state machine according to the OTG spec */
 struct otg_fsm {
 	/* Input */
+	int id;
+	int adp_change;
+	int power_up;
+	int test_device;
+	int a_bus_drop;
+	int a_bus_req;
+	int a_srp_det;
+	int a_vbus_vld;
+	int b_conn;
 	int a_bus_resume;
 	int a_bus_suspend;
 	int a_conn;
+	int b_bus_req;
+	int b_se0_srp;
+	int b_ssend_srp;
+	int b_sess_vld;
+	/* Auxilary inputs */
 	int a_sess_vld;
-	int a_srp_det;
-	int a_vbus_vld;
 	int b_bus_resume;
 	int b_bus_suspend;
-	int b_conn;
-	int b_se0_srp;
-	int b_sess_end;
-	int b_sess_vld;
-	int id;
+
+	/* Output */
+	int data_pulse;
+	int drv_vbus;
+	int loc_conn;
+	int loc_sof;
+	int adp_prb;
+	int adp_sns;
 
 	/* Internal variables */
 	int a_set_b_hnp_en;
 	int b_srp_done;
 	int b_hnp_enable;
+	int a_clr_err;
+
+	/* Informative variables */
+	int a_bus_drop_inf;
+	int a_bus_req_inf;
+	int a_clr_err_inf;
+	int b_bus_req_inf;
+	/* Auxilary informative variables */
+	int a_suspend_req_inf;
 
 	/* Timeout indicator for timers */
 	int a_wait_vrise_tmout;
+	int a_wait_vfall_tmout;
 	int a_wait_bcon_tmout;
 	int a_aidl_bdis_tmout;
 	int b_ase0_brst_tmout;
-
-	/* Informative variables */
-	int a_bus_drop;
-	int a_bus_req;
-	int a_clr_err;
-	int a_suspend_req;
-	int b_bus_req;
-
-	/* Output */
-	int drv_vbus;
-	int loc_conn;
-	int loc_sof;
+	int a_bidl_adis_tmout;
 
 	struct otg_fsm_ops *ops;
 	struct usb_otg *otg;
@@ -83,65 +114,123 @@ struct otg_fsm {
 };
 
 struct otg_fsm_ops {
-	void	(*chrg_vbus)(int on);
-	void	(*drv_vbus)(int on);
-	void	(*loc_conn)(int on);
-	void	(*loc_sof)(int on);
-	void	(*start_pulse)(void);
-	void	(*add_timer)(void *timer);
-	void	(*del_timer)(void *timer);
+	void	(*chrg_vbus)(struct otg_fsm *fsm, int on);
+	void	(*drv_vbus)(struct otg_fsm *fsm, int on);
+	void	(*loc_conn)(struct otg_fsm *fsm, int on);
+	void	(*loc_sof)(struct otg_fsm *fsm, int on);
+	void	(*start_pulse)(struct otg_fsm *fsm);
+	void	(*start_adp_prb)(struct otg_fsm *fsm);
+	void	(*start_adp_sns)(struct otg_fsm *fsm);
+	void	(*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
+	void	(*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
 	int	(*start_host)(struct otg_fsm *fsm, int on);
 	int	(*start_gadget)(struct otg_fsm *fsm, int on);
 };
 
 
-static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on)
+static inline int otg_chrg_vbus(struct otg_fsm *fsm, int on)
 {
-	fsm->ops->chrg_vbus(on);
+	if (!fsm->ops->chrg_vbus)
+		return -EOPNOTSUPP;
+	fsm->ops->chrg_vbus(fsm, on);
+	return 0;
 }
 
-static inline void otg_drv_vbus(struct otg_fsm *fsm, int on)
+static inline int otg_drv_vbus(struct otg_fsm *fsm, int on)
 {
+	if (!fsm->ops->drv_vbus)
+		return -EOPNOTSUPP;
 	if (fsm->drv_vbus != on) {
 		fsm->drv_vbus = on;
-		fsm->ops->drv_vbus(on);
+		fsm->ops->drv_vbus(fsm, on);
 	}
+	return 0;
 }
 
-static inline void otg_loc_conn(struct otg_fsm *fsm, int on)
+static inline int otg_loc_conn(struct otg_fsm *fsm, int on)
 {
+	if (!fsm->ops->loc_conn)
+		return -EOPNOTSUPP;
 	if (fsm->loc_conn != on) {
 		fsm->loc_conn = on;
-		fsm->ops->loc_conn(on);
+		fsm->ops->loc_conn(fsm, on);
 	}
+	return 0;
 }
 
-static inline void otg_loc_sof(struct otg_fsm *fsm, int on)
+static inline int otg_loc_sof(struct otg_fsm *fsm, int on)
 {
+	if (!fsm->ops->loc_sof)
+		return -EOPNOTSUPP;
 	if (fsm->loc_sof != on) {
 		fsm->loc_sof = on;
-		fsm->ops->loc_sof(on);
+		fsm->ops->loc_sof(fsm, on);
+	}
+	return 0;
+}
+
+static inline int otg_start_pulse(struct otg_fsm *fsm)
+{
+	if (!fsm->ops->start_pulse)
+		return -EOPNOTSUPP;
+	if (!fsm->data_pulse) {
+		fsm->data_pulse = 1;
+		fsm->ops->start_pulse(fsm);
 	}
+	return 0;
 }
 
-static inline void otg_start_pulse(struct otg_fsm *fsm)
+static inline int otg_start_adp_prb(struct otg_fsm *fsm)
 {
-	fsm->ops->start_pulse();
+	if (!fsm->ops->start_adp_prb)
+		return -EOPNOTSUPP;
+	if (!fsm->adp_prb) {
+		fsm->adp_sns = 0;
+		fsm->adp_prb = 1;
+		fsm->ops->start_adp_prb(fsm);
+	}
+	return 0;
 }
 
-static inline void otg_add_timer(struct otg_fsm *fsm, void *timer)
+static inline int otg_start_adp_sns(struct otg_fsm *fsm)
 {
-	fsm->ops->add_timer(timer);
+	if (!fsm->ops->start_adp_sns)
+		return -EOPNOTSUPP;
+	if (!fsm->adp_sns) {
+		fsm->adp_sns = 1;
+		fsm->ops->start_adp_sns(fsm);
+	}
+	return 0;
 }
 
-static inline void otg_del_timer(struct otg_fsm *fsm, void *timer)
+static inline int otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer)
 {
-	fsm->ops->del_timer(timer);
+	if (!fsm->ops->add_timer)
+		return -EOPNOTSUPP;
+	fsm->ops->add_timer(fsm, timer);
+	return 0;
 }
 
-int otg_statemachine(struct otg_fsm *fsm);
+static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer)
+{
+	if (!fsm->ops->del_timer)
+		return -EOPNOTSUPP;
+	fsm->ops->del_timer(fsm, timer);
+	return 0;
+}
 
-/* Defined by device specific driver, for different timer implementation */
-extern struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr,
-	*a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr,
-	*a_wait_enum_tmr;
+static inline int otg_start_host(struct otg_fsm *fsm, int on)
+{
+	if (!fsm->ops->start_host)
+		return -EOPNOTSUPP;
+	return fsm->ops->start_host(fsm, on);
+}
+
+static inline int otg_start_gadget(struct otg_fsm *fsm, int on)
+{
+	if (!fsm->ops->start_gadget)
+		return -EOPNOTSUPP;
+	return fsm->ops->start_gadget(fsm, on);
+}
+
+int otg_statemachine(struct otg_fsm *fsm);
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index efe59f3f7fda..fce3a9e9bb5d 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -35,6 +35,9 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
 
 #include "phy-generic.h"
 
@@ -64,6 +67,23 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
 	return 0;
 }
 
+static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted)
+{
+	int value;
+
+	if (!gpio_is_valid(nop->gpio_reset))
+		return;
+
+	value = asserted;
+	if (nop->reset_active_low)
+		value = !value;
+
+	gpio_set_value_cansleep(nop->gpio_reset, value);
+
+	if (!asserted)
+		usleep_range(10000, 20000);
+}
+
 int usb_gen_phy_init(struct usb_phy *phy)
 {
 	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
@@ -74,13 +94,10 @@ int usb_gen_phy_init(struct usb_phy *phy)
 	}
 
 	if (!IS_ERR(nop->clk))
-		clk_enable(nop->clk);
+		clk_prepare_enable(nop->clk);
 
-	if (!IS_ERR(nop->reset)) {
-		/* De-assert RESET */
-		if (regulator_enable(nop->reset))
-			dev_err(phy->dev, "Failed to de-assert reset\n");
-	}
+	/* De-assert RESET */
+	nop_reset_set(nop, 0);
 
 	return 0;
 }
@@ -90,14 +107,11 @@ void usb_gen_phy_shutdown(struct usb_phy *phy)
 {
 	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
 
-	if (!IS_ERR(nop->reset)) {
-		/* Assert RESET */
-		if (regulator_disable(nop->reset))
-			dev_err(phy->dev, "Failed to assert reset\n");
-	}
+	/* Assert RESET */
+	nop_reset_set(nop, 1);
 
 	if (!IS_ERR(nop->clk))
-		clk_disable(nop->clk);
+		clk_disable_unprepare(nop->clk);
 
 	if (!IS_ERR(nop->vcc)) {
 		if (regulator_disable(nop->vcc))
@@ -136,8 +150,7 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
 }
 
 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
-		enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
-		bool needs_reset)
+		enum usb_phy_type type, u32 clk_rate, bool needs_vcc)
 {
 	int err;
 
@@ -160,14 +173,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
 		}
 	}
 
-	if (!IS_ERR(nop->clk)) {
-		err = clk_prepare(nop->clk);
-		if (err) {
-			dev_err(dev, "Error preparing clock\n");
-			return err;
-		}
-	}
-
 	nop->vcc = devm_regulator_get(dev, "vcc");
 	if (IS_ERR(nop->vcc)) {
 		dev_dbg(dev, "Error getting vcc regulator: %ld\n",
@@ -176,12 +181,22 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
 			return -EPROBE_DEFER;
 	}
 
-	nop->reset = devm_regulator_get(dev, "reset");
-	if (IS_ERR(nop->reset)) {
-		dev_dbg(dev, "Error getting reset regulator: %ld\n",
-					PTR_ERR(nop->reset));
-		if (needs_reset)
-			return -EPROBE_DEFER;
+	if (gpio_is_valid(nop->gpio_reset)) {
+		unsigned long gpio_flags;
+
+		/* Assert RESET */
+		if (nop->reset_active_low)
+			gpio_flags = GPIOF_OUT_INIT_LOW;
+		else
+			gpio_flags = GPIOF_OUT_INIT_HIGH;
+
+		err = devm_gpio_request_one(dev, nop->gpio_reset,
+						gpio_flags, dev_name(dev));
+		if (err) {
+			dev_err(dev, "Error requesting RESET GPIO %d\n",
+					nop->gpio_reset);
+			return err;
+		}
 	}
 
 	nop->dev		= dev;
@@ -200,13 +215,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
 }
 EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
 
-void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop)
-{
-	if (!IS_ERR(nop->clk))
-		clk_unprepare(nop->clk);
-}
-EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy);
-
 static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -217,31 +225,36 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate = 0;
 	bool needs_vcc = false;
-	bool needs_reset = false;
+
+	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
+	if (!nop)
+		return -ENOMEM;
+
+	nop->reset_active_low = true;	/* default behaviour */
 
 	if (dev->of_node) {
 		struct device_node *node = dev->of_node;
+		enum of_gpio_flags flags;
 
 		if (of_property_read_u32(node, "clock-frequency", &clk_rate))
 			clk_rate = 0;
 
 		needs_vcc = of_property_read_bool(node, "vcc-supply");
-		needs_reset = of_property_read_bool(node, "reset-supply");
+		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
+								0, &flags);
+		if (nop->gpio_reset == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+
+		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
 
 	} else if (pdata) {
 		type = pdata->type;
 		clk_rate = pdata->clk_rate;
 		needs_vcc = pdata->needs_vcc;
-		needs_reset = pdata->needs_reset;
+		nop->gpio_reset = pdata->gpio_reset;
 	}
 
-	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
-	if (!nop)
-		return -ENOMEM;
-
-
-	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc,
-			needs_reset);
+	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc);
 	if (err)
 		return err;
 
@@ -252,15 +265,13 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
 	if (err) {
 		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 			err);
-		goto err_add;
+		return err;
 	}
 
 	platform_set_drvdata(pdev, nop);
 
 	return 0;
 
-err_add:
-	usb_phy_gen_cleanup_phy(nop);
 	return err;
 }
 
@@ -268,7 +279,6 @@ static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
 {
 	struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev);
 
-	usb_phy_gen_cleanup_phy(nop);
 	usb_remove_phy(&nop->phy);
 
 	return 0;
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
index 61687d5a965b..d2a220d81734 100644
--- a/drivers/usb/phy/phy-generic.h
+++ b/drivers/usb/phy/phy-generic.h
@@ -6,15 +6,14 @@ struct usb_phy_gen_xceiv {
 	struct device *dev;
 	struct clk *clk;
 	struct regulator *vcc;
-	struct regulator *reset;
+	int gpio_reset;
+	bool reset_active_low;
 };
 
 int usb_gen_phy_init(struct usb_phy *phy);
 void usb_gen_phy_shutdown(struct usb_phy *phy);
 
 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
-		enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
-		bool needs_reset);
-void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop);
+		enum usb_phy_type type, u32 clk_rate, bool needs_vcc);
 
 #endif
diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c
new file mode 100644
index 000000000000..a99a6953f11c
--- /dev/null
+++ b/drivers/usb/phy/phy-rcar-gen2-usb.c
@@ -0,0 +1,248 @@
+/*
+ * Renesas R-Car Gen2 USB phy driver
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_data/usb-rcar-gen2-phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/usb/otg.h>
+
+struct rcar_gen2_usb_phy_priv {
+	struct usb_phy phy;
+	void __iomem *base;
+	struct clk *clk;
+	spinlock_t lock;
+	int usecount;
+	u32 ugctrl2;
+};
+
+#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy)
+
+/* Low Power Status register */
+#define USBHS_LPSTS_REG			0x02
+#define USBHS_LPSTS_SUSPM		(1 << 14)
+
+/* USB General control register */
+#define USBHS_UGCTRL_REG		0x80
+#define USBHS_UGCTRL_CONNECT		(1 << 2)
+#define USBHS_UGCTRL_PLLRESET		(1 << 0)
+
+/* USB General control register 2 */
+#define USBHS_UGCTRL2_REG		0x84
+#define USBHS_UGCTRL2_USB0_PCI		(1 << 4)
+#define USBHS_UGCTRL2_USB0_HS		(3 << 4)
+#define USBHS_UGCTRL2_USB2_PCI		(0 << 31)
+#define USBHS_UGCTRL2_USB2_SS		(1 << 31)
+
+/* USB General status register */
+#define USBHS_UGSTS_REG			0x88
+#define USBHS_UGSTS_LOCK		(3 << 8)
+
+/* Enable USBHS internal phy */
+static int __rcar_gen2_usbhs_phy_enable(void __iomem *base)
+{
+	u32 val;
+	int i;
+
+	/* USBHS PHY power on */
+	val = ioread32(base + USBHS_UGCTRL_REG);
+	val &= ~USBHS_UGCTRL_PLLRESET;
+	iowrite32(val, base + USBHS_UGCTRL_REG);
+
+	val = ioread16(base + USBHS_LPSTS_REG);
+	val |= USBHS_LPSTS_SUSPM;
+	iowrite16(val, base + USBHS_LPSTS_REG);
+
+	for (i = 0; i < 20; i++) {
+		val = ioread32(base + USBHS_UGSTS_REG);
+		if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {
+			val = ioread32(base + USBHS_UGCTRL_REG);
+			val |= USBHS_UGCTRL_CONNECT;
+			iowrite32(val, base + USBHS_UGCTRL_REG);
+			return 0;
+		}
+		udelay(1);
+	}
+
+	/* Timed out waiting for the PLL lock */
+	return -ETIMEDOUT;
+}
+
+/* Disable USBHS internal phy */
+static int __rcar_gen2_usbhs_phy_disable(void __iomem *base)
+{
+	u32 val;
+
+	/* USBHS PHY power off */
+	val = ioread32(base + USBHS_UGCTRL_REG);
+	val &= ~USBHS_UGCTRL_CONNECT;
+	iowrite32(val, base + USBHS_UGCTRL_REG);
+
+	val = ioread16(base + USBHS_LPSTS_REG);
+	val &= ~USBHS_LPSTS_SUSPM;
+	iowrite16(val, base + USBHS_LPSTS_REG);
+
+	val = ioread32(base + USBHS_UGCTRL_REG);
+	val |= USBHS_UGCTRL_PLLRESET;
+	iowrite32(val, base + USBHS_UGCTRL_REG);
+	return 0;
+}
+
+/* Setup USB channels */
+static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv)
+{
+	u32 val;
+
+	clk_prepare_enable(priv->clk);
+
+	/* Set USB channels in the USBHS UGCTRL2 register */
+	val = ioread32(priv->base);
+	val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS);
+	val |= priv->ugctrl2;
+	iowrite32(val, priv->base);
+}
+
+/* Shutdown USB channels */
+static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv)
+{
+	__rcar_gen2_usbhs_phy_disable(priv->base);
+	clk_disable_unprepare(priv->clk);
+}
+
+static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend)
+{
+	struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy);
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) :
+			   __rcar_gen2_usbhs_phy_enable(priv->base);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return retval;
+}
+
+static int rcar_gen2_usb_phy_init(struct usb_phy *phy)
+{
+	struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	/*
+	 * Enable the clock and setup USB channels
+	 * if it's the first user
+	 */
+	if (!priv->usecount++)
+		__rcar_gen2_usb_phy_init(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return 0;
+}
+
+static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy)
+{
+	struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!priv->usecount) {
+		dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n");
+		goto out;
+	}
+
+	/* Disable everything if it's the last user */
+	if (!--priv->usecount)
+		__rcar_gen2_usb_phy_shutdown(priv);
+out:
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int rcar_gen2_usb_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rcar_gen2_phy_platform_data *pdata;
+	struct rcar_gen2_usb_phy_priv *priv;
+	struct resource *res;
+	void __iomem *base;
+	struct clk *clk;
+	int retval;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(dev, "No platform data\n");
+		return -EINVAL;
+	}
+
+	clk = devm_clk_get(&pdev->dev, "usbhs");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Can't get the clock\n");
+		return PTR_ERR(clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(dev, "Memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&priv->lock);
+	priv->clk = clk;
+	priv->base = base;
+	priv->ugctrl2 = pdata->chan0_pci ?
+			USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS;
+	priv->ugctrl2 |= pdata->chan2_pci ?
+			USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS;
+	priv->phy.dev = dev;
+	priv->phy.label = dev_name(dev);
+	priv->phy.init = rcar_gen2_usb_phy_init;
+	priv->phy.shutdown = rcar_gen2_usb_phy_shutdown;
+	priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend;
+
+	retval = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
+	if (retval < 0) {
+		dev_err(dev, "Failed to add USB phy\n");
+		return retval;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	return retval;
+}
+
+static int rcar_gen2_usb_phy_remove(struct platform_device *pdev)
+{
+	struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&priv->phy);
+
+	return 0;
+}
+
+static struct platform_driver rcar_gen2_usb_phy_driver = {
+	.driver = {
+		.name = "usb_phy_rcar_gen2",
+	},
+	.probe = rcar_gen2_usb_phy_probe,
+	.remove = rcar_gen2_usb_phy_remove,
+};
+
+module_platform_driver(rcar_gen2_usb_phy_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy");
+MODULE_AUTHOR("Valentine Barshak <valentine.barshak@cogentembedded.com>");
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index e9cb1cb8abc7..82232acf1ab6 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -1090,7 +1090,7 @@ static struct platform_driver tegra_usb_phy_driver = {
 	.driver		= {
 		.name	= "tegra-phy",
 		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(tegra_usb_phy_id_table),
+		.of_match_table = tegra_usb_phy_id_table,
 	},
 };
 module_platform_driver(tegra_usb_phy_driver);
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 16dbc9382678..30e8a61552d4 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -33,6 +33,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 
 /* usb register definitions */
 #define USB_VENDOR_ID_LSB		0x00
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index a9984c700d2c..1b74523e1fee 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -98,7 +98,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
 
 	ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
 	if (!ptr)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	phy = usb_get_phy(type);
 	if (!IS_ERR(phy)) {