This helper allows board support code to add the PHY's VCC and RESET regulators which are GPIO controlled as well as the NOP PHY device. Signed-off-by: Roger Quadros <rogerq@xxxxxx> --- arch/arm/mach-omap2/usb-host.c | 177 +++++++++++++++++++++++++++++++++++++++- arch/arm/mach-omap2/usb.h | 9 ++ 2 files changed, 184 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 5706bdc..49a2c3f 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 <asm/io.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/string.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/usb/phy.h> #include "soc.h" #include "omap_device.h" @@ -526,3 +530,172 @@ void __init usbhs_init(struct usbhs_omap_platform_data *pdata) } #endif + +/* 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, +}; + +static const char *reset_supply = "reset"; +static const char *vcc_supply = "vcc"; +static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */ + +int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) +{ + struct regulator_consumer_supply *supplies; + struct regulator_init_data *reg_data; + struct fixed_voltage_config *config; + char *supply_name; + int i, len; + struct platform_device *pdev; + char *phy_id; + + /* the phy_id will be something like "nop_usb_xceiv.1" */ + len = strlen(nop_name) + 3; /* 3 -> ".1" and NULL terminator */ + + for (i = 0; i < num_phys; i++) { + + if (!phy->port) { + pr_err("%s: Invalid port 0. Must start from 1\n", + __func__); + continue; + } + + /* do we need a NOP PHY device ? */ + if (!gpio_is_valid(phy->reset_gpio) && + !gpio_is_valid(phy->vcc_gpio)) + continue; + + /* create a NOP PHY device */ + pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->id = phy->port; + pdev->name = nop_name; + pdev->dev.platform_data = phy->platform_data; + + phy_id = kmalloc(len, GFP_KERNEL); + if (!phy_id) + return -ENOMEM; + + scnprintf(phy_id, len, "nop_usb_xceiv.%d\n", + pdev->id); + + if (platform_device_register(pdev)) { + pr_err("%s: Failed to register device %s\n", + __func__, phy_id); + continue; + } + + usb_bind_phy("ehci-omap.0", phy->port - 1, phy_id); + + /* Do we need RESET regulator ? */ + 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_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(13, GFP_KERNEL); + if (!supply_name) + return -ENOMEM; + + scnprintf(supply_name, 13, "hsusb%d_reset", phy->port); + 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: + /* Do we need VCC regulator? */ + 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_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(13, GFP_KERNEL); + if (!supply_name) + return -ENOMEM; + + scnprintf(supply_name, 13, "hsusb%d_vcc", phy->port); + 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; +} diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h index 3319f5c..e7261eb 100644 --- a/arch/arm/mach-omap2/usb.h +++ b/arch/arm/mach-omap2/usb.h @@ -53,8 +53,17 @@ #define USBPHY_OTGSESSEND_EN (1 << 20) #define USBPHY_DATA_POLARITY (1 << 23) +struct usbhs_phy_data { + int port; /* 1 indexed port number */ + int reset_gpio; + int vcc_gpio; + bool vcc_polarity; /* 1 active high, 0 active low */ + void *platform_data; +}; + 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, int num_phys); extern void am35x_musb_reset(void); extern void am35x_musb_phy_power(u8 on); -- 1.7.4.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html