diff mbox

[00/24] ARM: OMAP2+: Adapt to ehci-omap changes for 3.10

Message ID 5141EFAE.2040809@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Roger Quadros March 14, 2013, 3:41 p.m. UTC
On 03/13/2013 06:57 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [130313 09:40]:
>> On 03/13/2013 06:24 PM, Tony Lindgren wrote:
>>> * Roger Quadros <rogerq@ti.com> [130313 06:46]:
>>>> On 03/12/2013 06:40 PM, Tony Lindgren wrote:
>>>>> * Roger Quadros <rogerq@ti.com> [130312 04:47]:
>>>>>> Hi Tony,
>>>>>>
>>>>>> These patches provide the SoC side code required to support
>>>>>> the changes in the OMAP USB Host drivers done in [1], [2] & [3].
>>>>> ... 
>>>>>
>>>>>>  arch/arm/mach-omap2/board-3430sdp.c                |   97 +++++++++++++++-
>>>>>>  arch/arm/mach-omap2/board-3630sdp.c                |  100 +++++++++++++++-
>>>>>>  arch/arm/mach-omap2/board-am3517crane.c            |   95 +++++++++++++--
>>>>>>  arch/arm/mach-omap2/board-am3517evm.c              |   66 ++++++++++-
>>>>>>  arch/arm/mach-omap2/board-cm-t35.c                 |   95 ++++++++++++++-
>>>>>>  arch/arm/mach-omap2/board-cm-t3517.c               |   97 +++++++++++++++-
>>>>>>  arch/arm/mach-omap2/board-devkit8000.c             |   20 ++--
>>>>>>  arch/arm/mach-omap2/board-generic.c                |   67 +++++++++++
>>>>>>  arch/arm/mach-omap2/board-igep0020.c               |  112 ++++++++++++++++---
>>>>>>  arch/arm/mach-omap2/board-omap3beagle.c            |   93 +++++++++++++--
>>>>>>  arch/arm/mach-omap2/board-omap3evm.c               |   62 ++++++++--
>>>>>>  arch/arm/mach-omap2/board-omap3pandora.c           |   52 +++++++--
>>>>>>  arch/arm/mach-omap2/board-omap3stalker.c           |   52 +++++++-
>>>>>>  arch/arm/mach-omap2/board-omap3touchbook.c         |   62 +++++++++-
>>>>>>  arch/arm/mach-omap2/board-omap4panda.c             |  122 ++++++++++++++------
>>>>>>  arch/arm/mach-omap2/board-overo.c                  |   54 ++++++++-
>>>>>>  arch/arm/mach-omap2/board-zoom.c                   |   56 ++++++++-
>>>>>
>>>>> Can't you have some mach-omap2/ehci-common.c that takes care
>>>>> of the initializiation to avoid this much addition to the
>>>>> board-*.c files? You may be able to have just a common function
>>>>> to do it and pass few parameters?
>>>>
>>>> Since we moved reset and power handling for the USB PHYs from omap-echi
>>>> driver into the USB PHY driver we need to define the regulator data
>>>> for RESET and Power line of each PHY. So most of the code added is just
>>>> regulator data for the PHY rather than omap-ehci.
>>>
>>> It seems that you're now repeating minor variations of the same PHY
>>> over and over again though.
>>
>> Yes it is the vcc and reset regulator data for the PHY that
>> is getting repeated with variations in the GPIO number.
>>
>>>  
>>>> Instead of a common function, I can implement some macros that make it
>>>> easier to define the regulators for the PHY in the board files.
>>>> Does this sound OK?
>>>>
>>>> Personally I don't like such macros because it hides the implementation
>>>> and is difficult to read/debug.
>>>
>>> I'd prefer a common function to initialize the PHY though as it sounds
>>> like using macros would just allocate similar PHY many times which seems
>>> unnecessary.
>>>
>> OK, so we want to create the regulator data at runtime to save some memory?
>> I'll come up with something.
> 
> Or I guess you can have just one instance that gets filled in by some PHY
> platform init function.
> 

OK. Let me know how the below patch looks. After that, the board code
will look like.

static struct usbhs_phy_data phy_data[] = {
	{
		.reset_gpio = 147,
		.vcc_gpio = 148
		.vcc_polarity = 1,
		.phy_id = "nop_usb_xceiv.2",
	},
	{}, /* Terminator */
};

usbhs_init_phys(phy_data);

Patch to implement usbhs_init_phys();

 #define USBPHY_DATA_POLARITY	(1 << 23)
 
+struct usbhs_phy_data {
+	int reset_gpio;
+	int vcc_gpio;
+	bool vcc_polarity;	/* 1 active high, 0 active low */
+	char *phy_id;
+};
+
 extern void usb_musb_init(struct omap_musb_board_data *board_data);
 extern void usbhs_init(struct usbhs_omap_platform_data *pdata);
+extern int usbhs_init_phys(struct usbhs_phy_data *phy);
 
 extern void am35x_musb_reset(void);
 extern void am35x_musb_phy_power(u8 on);

--
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Tony Lindgren March 14, 2013, 4:54 p.m. UTC | #1
* Roger Quadros <rogerq@ti.com> [130314 08:45]:
> 
> OK. Let me know how the below patch looks. After that, the board code
> will look like.
> 
> static struct usbhs_phy_data phy_data[] = {
> 	{
> 		.reset_gpio = 147,
> 		.vcc_gpio = 148
> 		.vcc_polarity = 1,
> 		.phy_id = "nop_usb_xceiv.2",
> 	},
> 	{}, /* Terminator */
> };
> 
> usbhs_init_phys(phy_data);

Great, looks good to me.
 
> Patch to implement usbhs_init_phys();
> 
> diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
> index 5706bdc..b9d6bff 100644
> --- a/arch/arm/mach-omap2/usb-host.c
> +++ b/arch/arm/mach-omap2/usb-host.c
> @@ -22,8 +22,12 @@
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/fixed.h>
> +#include <linux/string.h>
>  
>  #include <asm/io.h>
> +#include <asm/gpio.h>

Please change these both to linux/io.h and linux/gpio.h.
  
>  #include "soc.h"
>  #include "omap_device.h"
> @@ -472,6 +476,141 @@ void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
>  	}
>  }
>  
> +static const char *reset_supply = "reset";
> +static const char *vcc_supply = "vcc";
> +
> +/* Template for PHY regulators */
> +static struct regulator_consumer_supply hsusb_reg_supplies[] = {
> +	{ /* .supply & .dev_name filled later */ },
> +};
> +
> +static struct regulator_init_data hsusb_reg_data = {
> +	.constraints = {
> +		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
> +	},
> +	.consumer_supplies	= hsusb_reg_supplies,
> +	.num_consumer_supplies	= ARRAY_SIZE(hsusb_reg_supplies),
> +};
> +
> +static struct fixed_voltage_config hsusb_reg_config = {
> +	/* .supply_name filled later */
> +	.microvolts = 3300000,
> +	.gpio = -1,		/* updated later */
> +	.startup_delay = 70000, /* 70msec */
> +	.enable_high = 1,	/* updated later */
> +	.enabled_at_boot = 0,	/* keep in RESET */
> +	/* .init_data filled later */
> +};
> +
> +static struct platform_device_info hsusb_reg_pdev_info = {
> +	.name	= "reg-fixed-voltage",
> +	.id	= PLATFORM_DEVID_AUTO,
> +};
> +
> +int __init usbhs_init_phys(struct usbhs_phy_data *phy)
> +{
> +	struct regulator_consumer_supply *supplies;
> +	struct regulator_init_data *reg_data;
> +	struct fixed_voltage_config *config;
> +	char *supply_name;
> +	int i;
> +
> +
> +	for (i = 1; i <= OMAP3_HS_USB_PORTS; i++) {

Maybe pass the number of ports to initialize too to the
function? Might be more future proof, although it will only
be needed until we have converted to DT.

> +
> +		if (!phy->phy_id)	/* Terminator ? */
> +			break;
> +
> +		if (!gpio_is_valid(phy->reset_gpio))
> +			goto check_vcc;
> +
> +		supplies = kmemdup(hsusb_reg_supplies,
> +			    ARRAY_SIZE(hsusb_reg_supplies) *
> +			    sizeof(struct regulator_consumer_supply),
> +			    GFP_KERNEL);
> +		if (!supplies)
> +			return -ENOMEM;
> +
> +		supplies->supply = reset_supply;
> +		supplies->dev_name = phy->phy_id;
> +
> +		reg_data = kmemdup(&hsusb_reg_data, sizeof(hsusb_reg_data),
> +							GFP_KERNEL);
> +		if (!reg_data)
> +			return -ENOMEM;
> +
> +		reg_data->consumer_supplies = supplies;
> +
> +		config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config),
> +							GFP_KERNEL);
> +		if (!config)
> +			return -ENOMEM;
> +
> +		supply_name = kmalloc(14, GFP_KERNEL);
> +		if (!supply_name)
> +			return -ENOMEM;
> +
> +		scnprintf(supply_name, 13, "hsusb%d_reset", i);
> +		config->supply_name = supply_name;
> +		config->gpio = phy->reset_gpio;
> +		config->init_data = reg_data;
> +
> +		hsusb_reg_pdev_info.data = config;
> +		hsusb_reg_pdev_info.size_data = sizeof(hsusb_reg_config);
> +		platform_device_register_full(&hsusb_reg_pdev_info);
> +
> +check_vcc:
> +		if (!gpio_is_valid(phy->vcc_gpio))
> +			goto next;
> +
> +		supplies = kmemdup(hsusb_reg_supplies,
> +			    ARRAY_SIZE(hsusb_reg_supplies) *
> +			    sizeof(struct regulator_consumer_supply),
> +			    GFP_KERNEL);
> +		if (!supplies)
> +			return -ENOMEM;
> +
> +		supplies->supply = vcc_supply;
> +		supplies->dev_name = phy->phy_id;
> +
> +		reg_data = kmemdup(&hsusb_reg_data, sizeof(hsusb_reg_data),
> +							GFP_KERNEL);
> +		if (!reg_data)
> +			return -ENOMEM;
> +
> +		reg_data->consumer_supplies = supplies;
> +
> +		config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config),
> +							GFP_KERNEL);
> +		if (!config)
> +			return -ENOMEM;
> +
> +		supply_name = kmalloc(14, GFP_KERNEL);
> +		if (!supply_name)
> +			return -ENOMEM;
> +
> +		scnprintf(supply_name, 13, "hsusb%d_vcc", i);
> +		config->supply_name = supply_name;
> +		config->gpio = phy->vcc_gpio;
> +		config->enable_high = phy->vcc_polarity;
> +		config->init_data = reg_data;
> +
> +		hsusb_reg_pdev_info.data = config;
> +		hsusb_reg_pdev_info.size_data = sizeof(hsusb_reg_config);
> +		platform_device_register_full(&hsusb_reg_pdev_info);
> +
> +next:
> +		phy++;
> +	}
> +
> +	return 0;
> +}
> +
>  void __init usbhs_init(struct usbhs_omap_platform_data *pdata)
>  {
>  	struct omap_hwmod	*uhh_hwm, *tll_hwm;
> diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h
> index 3319f5c..70a8c63 100644
> --- a/arch/arm/mach-omap2/usb.h
> +++ b/arch/arm/mach-omap2/usb.h
> @@ -53,8 +53,16 @@
>  #define USBPHY_OTGSESSEND_EN	(1 << 20)
>  #define USBPHY_DATA_POLARITY	(1 << 23)
>  
> +struct usbhs_phy_data {
> +	int reset_gpio;
> +	int vcc_gpio;
> +	bool vcc_polarity;	/* 1 active high, 0 active low */
> +	char *phy_id;
> +};
> +
>  extern void usb_musb_init(struct omap_musb_board_data *board_data);
>  extern void usbhs_init(struct usbhs_omap_platform_data *pdata);
> +extern int usbhs_init_phys(struct usbhs_phy_data *phy);

Maybe need a static inline version when no EHCI is selected?

Otherwise looks good to me, thanks for updating it.

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Roger Quadros March 15, 2013, 9:22 a.m. UTC | #2
On 03/14/2013 06:54 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [130314 08:45]:
>>
>> OK. Let me know how the below patch looks. After that, the board code
>> will look like.
>>
>> static struct usbhs_phy_data phy_data[] = {
>> 	{
>> 		.reset_gpio = 147,
>> 		.vcc_gpio = 148
>> 		.vcc_polarity = 1,
>> 		.phy_id = "nop_usb_xceiv.2",
>> 	},
>> 	{}, /* Terminator */
>> };
>>
>> usbhs_init_phys(phy_data);
> 
> Great, looks good to me.
>  
>> Patch to implement usbhs_init_phys();
>>
>> diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
>> index 5706bdc..b9d6bff 100644
>> --- a/arch/arm/mach-omap2/usb-host.c
>> +++ b/arch/arm/mach-omap2/usb-host.c
>> @@ -22,8 +22,12 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/slab.h>
>>  #include <linux/dma-mapping.h>
>> +#include <linux/regulator/machine.h>
>> +#include <linux/regulator/fixed.h>
>> +#include <linux/string.h>
>>  
>>  #include <asm/io.h>
>> +#include <asm/gpio.h>
> 
> Please change these both to linux/io.h and linux/gpio.h.

OK.

>   
>>  #include "soc.h"
>>  #include "omap_device.h"
>> @@ -472,6 +476,141 @@ void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
>>  	}
>>  }
>>  
>> +static const char *reset_supply = "reset";
>> +static const char *vcc_supply = "vcc";
>> +
>> +/* Template for PHY regulators */
>> +static struct regulator_consumer_supply hsusb_reg_supplies[] = {
>> +	{ /* .supply & .dev_name filled later */ },
>> +};
>> +
>> +static struct regulator_init_data hsusb_reg_data = {
>> +	.constraints = {
>> +		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
>> +	},
>> +	.consumer_supplies	= hsusb_reg_supplies,
>> +	.num_consumer_supplies	= ARRAY_SIZE(hsusb_reg_supplies),
>> +};
>> +
>> +static struct fixed_voltage_config hsusb_reg_config = {
>> +	/* .supply_name filled later */
>> +	.microvolts = 3300000,
>> +	.gpio = -1,		/* updated later */
>> +	.startup_delay = 70000, /* 70msec */
>> +	.enable_high = 1,	/* updated later */
>> +	.enabled_at_boot = 0,	/* keep in RESET */
>> +	/* .init_data filled later */
>> +};
>> +
>> +static struct platform_device_info hsusb_reg_pdev_info = {
>> +	.name	= "reg-fixed-voltage",
>> +	.id	= PLATFORM_DEVID_AUTO,
>> +};
>> +
>> +int __init usbhs_init_phys(struct usbhs_phy_data *phy)
>> +{
>> +	struct regulator_consumer_supply *supplies;
>> +	struct regulator_init_data *reg_data;
>> +	struct fixed_voltage_config *config;
>> +	char *supply_name;
>> +	int i;
>> +
>> +
>> +	for (i = 1; i <= OMAP3_HS_USB_PORTS; i++) {
> 
> Maybe pass the number of ports to initialize too to the
> function? Might be more future proof, although it will only
> be needed until we have converted to DT.
> 

OK. I'll add a port index parameter to the usbhs_phy_data structure
to indicate which port the data belongs to and a number of ports
to usbhs_init_phys()

board code can then do

static struct usbhs_phy_data phy_data[] = {
	{
		.port = 1,	/* First USB port */
		.reset_gpio = 147,
		.vcc_gpio = 148
		.vcc_polarity = 1,
		.phy_id = "nop_usb_xceiv.2",
	},
};

usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));

>> +
>> +		if (!phy->phy_id)	/* Terminator ? */
>> +			break;
>> +
>> +		if (!gpio_is_valid(phy->reset_gpio))
>> +			goto check_vcc;
>> +
>> +		supplies = kmemdup(hsusb_reg_supplies,
>> +			    ARRAY_SIZE(hsusb_reg_supplies) *
>> +			    sizeof(struct regulator_consumer_supply),
>> +			    GFP_KERNEL);
>> +		if (!supplies)
>> +			return -ENOMEM;
>> +
>> +		supplies->supply = reset_supply;
>> +		supplies->dev_name = phy->phy_id;
>> +
>> +		reg_data = kmemdup(&hsusb_reg_data, sizeof(hsusb_reg_data),
>> +							GFP_KERNEL);
>> +		if (!reg_data)
>> +			return -ENOMEM;
>> +
>> +		reg_data->consumer_supplies = supplies;
>> +
>> +		config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config),
>> +							GFP_KERNEL);
>> +		if (!config)
>> +			return -ENOMEM;
>> +
>> +		supply_name = kmalloc(14, GFP_KERNEL);
>> +		if (!supply_name)
>> +			return -ENOMEM;
>> +
>> +		scnprintf(supply_name, 13, "hsusb%d_reset", i);
>> +		config->supply_name = supply_name;
>> +		config->gpio = phy->reset_gpio;
>> +		config->init_data = reg_data;
>> +
>> +		hsusb_reg_pdev_info.data = config;
>> +		hsusb_reg_pdev_info.size_data = sizeof(hsusb_reg_config);
>> +		platform_device_register_full(&hsusb_reg_pdev_info);
>> +
>> +check_vcc:
>> +		if (!gpio_is_valid(phy->vcc_gpio))
>> +			goto next;
>> +
>> +		supplies = kmemdup(hsusb_reg_supplies,
>> +			    ARRAY_SIZE(hsusb_reg_supplies) *
>> +			    sizeof(struct regulator_consumer_supply),
>> +			    GFP_KERNEL);
>> +		if (!supplies)
>> +			return -ENOMEM;
>> +
>> +		supplies->supply = vcc_supply;
>> +		supplies->dev_name = phy->phy_id;
>> +
>> +		reg_data = kmemdup(&hsusb_reg_data, sizeof(hsusb_reg_data),
>> +							GFP_KERNEL);
>> +		if (!reg_data)
>> +			return -ENOMEM;
>> +
>> +		reg_data->consumer_supplies = supplies;
>> +
>> +		config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config),
>> +							GFP_KERNEL);
>> +		if (!config)
>> +			return -ENOMEM;
>> +
>> +		supply_name = kmalloc(14, GFP_KERNEL);
>> +		if (!supply_name)
>> +			return -ENOMEM;
>> +
>> +		scnprintf(supply_name, 13, "hsusb%d_vcc", i);
>> +		config->supply_name = supply_name;
>> +		config->gpio = phy->vcc_gpio;
>> +		config->enable_high = phy->vcc_polarity;
>> +		config->init_data = reg_data;
>> +
>> +		hsusb_reg_pdev_info.data = config;
>> +		hsusb_reg_pdev_info.size_data = sizeof(hsusb_reg_config);
>> +		platform_device_register_full(&hsusb_reg_pdev_info);
>> +
>> +next:
>> +		phy++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>  void __init usbhs_init(struct usbhs_omap_platform_data *pdata)
>>  {
>>  	struct omap_hwmod	*uhh_hwm, *tll_hwm;
>> diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h
>> index 3319f5c..70a8c63 100644
>> --- a/arch/arm/mach-omap2/usb.h
>> +++ b/arch/arm/mach-omap2/usb.h
>> @@ -53,8 +53,16 @@
>>  #define USBPHY_OTGSESSEND_EN	(1 << 20)
>>  #define USBPHY_DATA_POLARITY	(1 << 23)
>>  
>> +struct usbhs_phy_data {
>> +	int reset_gpio;
>> +	int vcc_gpio;
>> +	bool vcc_polarity;	/* 1 active high, 0 active low */
>> +	char *phy_id;
>> +};
>> +
>>  extern void usb_musb_init(struct omap_musb_board_data *board_data);
>>  extern void usbhs_init(struct usbhs_omap_platform_data *pdata);
>> +extern int usbhs_init_phys(struct usbhs_phy_data *phy);
> 
> Maybe need a static inline version when no EHCI is selected?
> 
Yes.

> Otherwise looks good to me, thanks for updating it.
> 

Cool. I'll update all boards and send it to you soon.

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 5706bdc..b9d6bff 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -22,8 +22,12 @@ 
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/string.h>
 
 #include <asm/io.h>
+#include <asm/gpio.h>
 
 #include "soc.h"
 #include "omap_device.h"
@@ -472,6 +476,141 @@  void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
 	}
 }
 
+static const char *reset_supply = "reset";
+static const char *vcc_supply = "vcc";
+
+/* Template for PHY regulators */
+static struct regulator_consumer_supply hsusb_reg_supplies[] = {
+	{ /* .supply & .dev_name filled later */ },
+};
+
+static struct regulator_init_data hsusb_reg_data = {
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+	.consumer_supplies	= hsusb_reg_supplies,
+	.num_consumer_supplies	= ARRAY_SIZE(hsusb_reg_supplies),
+};
+
+static struct fixed_voltage_config hsusb_reg_config = {
+	/* .supply_name filled later */
+	.microvolts = 3300000,
+	.gpio = -1,		/* updated later */
+	.startup_delay = 70000, /* 70msec */
+	.enable_high = 1,	/* updated later */
+	.enabled_at_boot = 0,	/* keep in RESET */
+	/* .init_data filled later */
+};
+
+static struct platform_device_info hsusb_reg_pdev_info = {
+	.name	= "reg-fixed-voltage",
+	.id	= PLATFORM_DEVID_AUTO,
+};
+
+int __init usbhs_init_phys(struct usbhs_phy_data *phy)
+{
+	struct regulator_consumer_supply *supplies;
+	struct regulator_init_data *reg_data;
+	struct fixed_voltage_config *config;
+	char *supply_name;
+	int i;
+
+
+	for (i = 1; i <= OMAP3_HS_USB_PORTS; i++) {
+
+		if (!phy->phy_id)	/* Terminator ? */
+			break;
+
+		if (!gpio_is_valid(phy->reset_gpio))
+			goto check_vcc;
+
+		supplies = kmemdup(hsusb_reg_supplies,
+			    ARRAY_SIZE(hsusb_reg_supplies) *
+			    sizeof(struct regulator_consumer_supply),
+			    GFP_KERNEL);
+		if (!supplies)
+			return -ENOMEM;
+
+		supplies->supply = reset_supply;
+		supplies->dev_name = phy->phy_id;
+
+		reg_data = kmemdup(&hsusb_reg_data, sizeof(hsusb_reg_data),
+							GFP_KERNEL);
+		if (!reg_data)
+			return -ENOMEM;
+
+		reg_data->consumer_supplies = supplies;
+
+		config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config),
+							GFP_KERNEL);
+		if (!config)
+			return -ENOMEM;
+
+		supply_name = kmalloc(14, GFP_KERNEL);
+		if (!supply_name)
+			return -ENOMEM;
+
+		scnprintf(supply_name, 13, "hsusb%d_reset", i);
+		config->supply_name = supply_name;
+		config->gpio = phy->reset_gpio;
+		config->init_data = reg_data;
+
+		hsusb_reg_pdev_info.data = config;
+		hsusb_reg_pdev_info.size_data = sizeof(hsusb_reg_config);
+		platform_device_register_full(&hsusb_reg_pdev_info);
+
+check_vcc:
+		if (!gpio_is_valid(phy->vcc_gpio))
+			goto next;
+
+		supplies = kmemdup(hsusb_reg_supplies,
+			    ARRAY_SIZE(hsusb_reg_supplies) *
+			    sizeof(struct regulator_consumer_supply),
+			    GFP_KERNEL);
+		if (!supplies)
+			return -ENOMEM;
+
+		supplies->supply = vcc_supply;
+		supplies->dev_name = phy->phy_id;
+
+		reg_data = kmemdup(&hsusb_reg_data, sizeof(hsusb_reg_data),
+							GFP_KERNEL);
+		if (!reg_data)
+			return -ENOMEM;
+
+		reg_data->consumer_supplies = supplies;
+
+		config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config),
+							GFP_KERNEL);
+		if (!config)
+			return -ENOMEM;
+
+		supply_name = kmalloc(14, GFP_KERNEL);
+		if (!supply_name)
+			return -ENOMEM;
+
+		scnprintf(supply_name, 13, "hsusb%d_vcc", i);
+		config->supply_name = supply_name;
+		config->gpio = phy->vcc_gpio;
+		config->enable_high = phy->vcc_polarity;
+		config->init_data = reg_data;
+
+		hsusb_reg_pdev_info.data = config;
+		hsusb_reg_pdev_info.size_data = sizeof(hsusb_reg_config);
+		platform_device_register_full(&hsusb_reg_pdev_info);
+
+next:
+		phy++;
+	}
+
+	return 0;
+}
+
 void __init usbhs_init(struct usbhs_omap_platform_data *pdata)
 {
 	struct omap_hwmod	*uhh_hwm, *tll_hwm;
diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h
index 3319f5c..70a8c63 100644
--- a/arch/arm/mach-omap2/usb.h
+++ b/arch/arm/mach-omap2/usb.h
@@ -53,8 +53,16 @@ 
 #define USBPHY_OTGSESSEND_EN	(1 << 20)