summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Konovalov <andrey.konovalov@linaro.org>2013-02-19 18:24:57 +0400
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-02-19 18:24:57 +0400
commite33868e91648b8a2aa4e694984ad017276fc507e (patch)
tree5de851377a6751c22a1b48c46e18c56744bd8412
parent6af1d1f287756c0470e433dc8b7e543809615456 (diff)
parent55190b88b62f62586953e3e7e52fa1af4c6eeae6 (diff)
Merge branch 'tracking-panda-fix-usb' into merge-linux-linaroll-20130219.0
-rw-r--r--Documentation/devicetree/bindings/arm/omap/usb-host.txt60
-rw-r--r--Documentation/devicetree/bindings/regulator/fixed-regulator.txt6
-rw-r--r--arch/arm/boot/dts/omap4-panda.dts54
-rw-r--r--arch/arm/boot/dts/omap4.dtsi5
-rw-r--r--arch/arm/mach-omap2/board-generic.c2
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c94
-rw-r--r--arch/arm/mach-omap2/cclock3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/cclock44xx_data.c37
-rw-r--r--arch/arm/mach-omap2/common.h2
-rw-r--r--arch/arm/mach-omap2/usb-host.c76
-rw-r--r--arch/arm/mach-omap2/usb.h4
-rw-r--r--drivers/mfd/omap-usb-host.c410
-rw-r--r--drivers/mfd/omap-usb-tll.c255
-rw-r--r--drivers/regulator/fixed.c6
-rw-r--r--drivers/usb/host/ehci-omap.c100
-rw-r--r--include/linux/platform_data/usb-omap.h4
16 files changed, 724 insertions, 393 deletions
diff --git a/Documentation/devicetree/bindings/arm/omap/usb-host.txt b/Documentation/devicetree/bindings/arm/omap/usb-host.txt
new file mode 100644
index 000000000000..f25cfa416c89
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/omap/usb-host.txt
@@ -0,0 +1,60 @@
+* usb-host - OMAP USB Host Subsystem
+
+The OMAP USB host subsystem consists of the following modules
+1) USBTLL (Tranceiverless interface)
+2) USBHOST (Host Controller module) which includes both EHCI and OHCI controllers
+
+THe USB Host subsystem can be connected to the external world using 3 PORTs that could
+be configured in various modes like UTMI+ for external PHY, ULPI transceiverless link (TLL),
+Serial TLL, High-speed interchip (HSIC), etc.
+
+Required proprties:
+- compatible: Must be "ti,usb-host";
+- num_ports: Number of physical ports available
+
+Optional properties:
+- 1 child node for each available port. These child nodes are usually supplied by the
+ board support device tree as they are specific to how the ports are wired on the board
+
+ - mode: Integer specifying the mode in which the port is used
+ * OMAP_USBHS_PORT_MODE_UNUSED = 0,
+ * OMAP_EHCI_PORT_MODE_PHY = 1,
+ * OMAP_EHCI_PORT_MODE_TLL = 2,
+ * OMAP_EHCI_PORT_MODE_HSIC = 3,
+ * OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0 = 4,
+ * OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM = 5,
+ * OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0 = 6,
+ * OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM = 7,
+ * OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0 = 8,
+ * OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM = 9,
+ * OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0 = 10,
+ * OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM = 11,
+ * OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0 = 12,
+ * OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM = 13,
+ - clk: Name of the clock that needs to be active when using the port
+ - clkrate: Frequency at which the above clk needs to be run at
+
+
+Example:
+
+/* In the OMAP Core tree */
+usbhost: usb-host {
+ compatible = "ti,usb-host";
+ num_ports = <3>;
+};
+
+/* In the Board tree */
+&usbhost {
+ port@0 {
+ mode = <1>;
+ clk = "auxclk3_ck";
+ clkrate = <19200000>;
+ };
+ port@1 {
+ mode = <0>;
+ };
+ port@2 {
+ mode = <0>;
+ };
+};
+
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 4fae41d54798..fe341147d1b4 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -7,10 +7,10 @@ Optional properties:
- gpio: gpio to use for enable control
- startup-delay-us: startup time in microseconds
- enable-active-high: Polarity of GPIO is Active high
-If this property is missing, the default assumed is Active low.
+ If this property is missing, the default assumed is Active low.
- gpio-open-drain: GPIO is open drain type.
If this property is missing then default assumption is false.
--vin-supply: Input supply name.
+- vin-supply: Input supply name.
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
@@ -30,5 +30,5 @@ Example:
enable-active-high;
regulator-boot-on;
gpio-open-drain;
- vin-supply = <&parent_reg>;
+ vin-supply = "input-supply-name";
};
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index 4122efe31cfd..1d98284ad3bf 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -57,6 +57,27 @@
"AFML", "Line In",
"AFMR", "Line In";
};
+
+ hubpower: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vhub0";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio1 1 0>; /* gpio 1 : HUB Power */
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
+
+ hubreset: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "hsusb0"; /* tag to associate with PORT 1 */
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 30 0>; /* gpio 62 : HUB & PHY Reset */
+ startup-delay-us = <70000>;
+ enable-active-high;
+ vin-supply = "vhub0"; /* Makes regulator f/w enable power before reset */
+ };
};
&omap4_pmx_core {
@@ -67,6 +88,7 @@
&mcbsp1_pins
&dss_hdmi_pins
&tpd12s015_pins
+ &usbb1_pins /* port 0 of omap usb host port pin mux configuration */
>;
twl6040_pins: pinmux_twl6040_pins {
@@ -110,6 +132,23 @@
0x58 0x10b /* hdmi_hpd.gpio_63 INPUT PULLDOWN | MODE3 */
>;
};
+
+ usbb1_pins: pinmux_usbb1_pins {
+ pinctrl-single,pins = <
+ 0x82 0x10C /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_clk INPUT | PULLDOWN */
+ 0x84 0x4 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_stp OUTPUT */
+ 0x86 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dir INPUT | PULLDOWN */
+ 0x88 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_nxt INPUT | PULLDOWN */
+ 0x8a 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat0 INPUT | PULLDOWN */
+ 0x8c 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat1 INPUT | PULLDOWN */
+ 0x8e 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat2 INPUT | PULLDOWN */
+ 0x90 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat3 INPUT | PULLDOWN */
+ 0x92 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat4 INPUT | PULLDOWN */
+ 0x94 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat5 INPUT | PULLDOWN */
+ 0x96 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat6 INPUT | PULLDOWN */
+ 0x98 0x104 /* USBB1_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat7 INPUT | PULLDOWN */
+ >;
+ };
};
&i2c1 {
@@ -136,6 +175,21 @@
};
};
+
+&usbhost {
+ port@0 {
+ mode = <1>; /* PHY mode */
+ clk = "auxclk3_ck"; /* PHY clock on FREF_CLK3_OUT */
+ clkrate = <19200000>;
+ };
+ port@1 {
+ mode = <0>;
+ };
+ port@2 {
+ mode = <0>;
+ };
+};
+
/include/ "twl6030.dtsi"
&i2c2 {
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 739bb79e410e..0900d44388c7 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -529,5 +529,10 @@
ti,hwmods = "timer11";
ti,timer-pwm;
};
+
+ usbhost: usb-host {
+ compatible = "ti,usb-host";
+ num_ports = <2>;
+ };
};
};
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 53cb380b7877..5c519aa59109 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -50,6 +50,8 @@ static void __init omap_generic_init(void)
omap4_panda_display_init_of();
else if (of_machine_is_compatible("ti,omap4-sdp"))
omap_4430sdp_display_init_of();
+
+ usbhost_init_of();
}
#ifdef CONFIG_SOC_OMAP2420
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 769c1feee1c4..884aecca547b 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -146,45 +146,73 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.phy_reset = false,
.reset_gpio_port[0] = -EINVAL,
.reset_gpio_port[1] = -EINVAL,
- .reset_gpio_port[2] = -EINVAL
+ .reset_gpio_port[2] = -EINVAL,
+ .clk[0] = "auxclk3_ck", /* FREF_CLK3 provides 19.2 MHz clock to PHY */
+ .clkrate[0] = 19200000,
};
-static struct gpio panda_ehci_gpios[] __initdata = {
- { GPIO_HUB_POWER, GPIOF_OUT_INIT_LOW, "hub_power" },
- { GPIO_HUB_NRESET, GPIOF_OUT_INIT_LOW, "hub_nreset" },
+/*
+ * hub_nreset also enables the ULPI PHY
+ * ULPI PHY is always powered
+ * hub_power enables a 3.3V regulator for (hub + eth) chip
+ * however there's no point having ULPI PHY in use alone
+ * since it's only connected to the (hub + eth) chip
+ */
+
+static struct regulator_init_data panda_hub = {
+ .constraints = {
+ .name = "vhub",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
};
-static void __init omap4_ehci_init(void)
-{
- int ret;
- struct clk *phy_ref_clk;
+static struct fixed_voltage_config panda_vhub = {
+ .supply_name = "vhub",
+ .microvolts = 3300000,
+ .gpio = GPIO_HUB_POWER,
+ .startup_delay = 70000, /* 70msec */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &panda_hub,
+};
- /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */
- phy_ref_clk = clk_get(NULL, "auxclk3_ck");
- if (IS_ERR(phy_ref_clk)) {
- pr_err("Cannot request auxclk3\n");
- return;
- }
- clk_set_rate(phy_ref_clk, 19200000);
- clk_prepare_enable(phy_ref_clk);
-
- /* disable the power to the usb hub prior to init and reset phy+hub */
- ret = gpio_request_array(panda_ehci_gpios,
- ARRAY_SIZE(panda_ehci_gpios));
- if (ret) {
- pr_err("Unable to initialize EHCI power/reset\n");
- return;
- }
+static struct platform_device omap_vhub_device = {
+ .name = "reg-fixed-voltage",
+ .id = 2,
+ .dev = {
+ .platform_data = &panda_vhub,
+ },
+};
- gpio_export(GPIO_HUB_POWER, 0);
- gpio_export(GPIO_HUB_NRESET, 0);
- gpio_set_value(GPIO_HUB_NRESET, 1);
+static struct regulator_init_data panda_ulpireset = {
+ /*
+ * idea is that when operating ulpireset, regulator api will make
+ * sure that the hub+eth chip is powered, since it's the "parent"
+ */
+ .supply_regulator = "vhub", /* we are a child of vhub */
+ .constraints = {
+ .name = "hsusb0",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+};
- usbhs_init(&usbhs_bdata);
+static struct fixed_voltage_config panda_vulpireset = {
+ .supply_name = "hsusb0", /* this name is magic for hsusb driver */
+ .microvolts = 3300000,
+ .gpio = GPIO_HUB_NRESET,
+ .startup_delay = 70000, /* 70msec */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &panda_ulpireset,
+};
- /* enable power to hub */
- gpio_set_value(GPIO_HUB_POWER, 1);
-}
+static struct platform_device omap_vulpireset_device = {
+ .name = "reg-fixed-voltage",
+ .id = 3,
+ .dev = {
+ .platform_data = &panda_vulpireset,
+ },
+};
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_UTMI,
@@ -443,10 +471,12 @@ static void __init omap4_panda_init(void)
omap4_panda_i2c_init();
platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
platform_device_register(&omap_vwlan_device);
+ platform_device_register(&omap_vhub_device);
+ platform_device_register(&omap_vulpireset_device);
omap_serial_init();
omap_sdrc_init(NULL, NULL);
omap4_twl6030_hsmmc_init(mmc);
- omap4_ehci_init();
+ usbhs_init(&usbhs_bdata);
usb_musb_init(&musb_board_data);
omap4_panda_display_init();
}
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index 6ef87580c33f..38669ce50530 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -3394,8 +3394,6 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs_omap", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK(NULL, "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
- CLK(NULL, "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
CLK(NULL, "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
CLK(NULL, "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
CLK(NULL, "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c
index a2cc046b47f4..846da90b2173 100644
--- a/arch/arm/mach-omap2/cclock44xx_data.c
+++ b/arch/arm/mach-omap2/cclock44xx_data.c
@@ -1404,10 +1404,17 @@ static struct clk_hw_omap usb_host_fs_fck_hw = {
DEFINE_STRUCT_CLK(usb_host_fs_fck, usb_host_fs_fck_parent_names,
usb_host_fs_fck_ops);
-static const char *utmi_p1_gfclk_parents[] = {
+static const struct clksel utmi_p1_clk_sel[] = {
+ { .parent = &init_60m_fclk, .rates = div_1_0_rates },
+ { .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+ { .parent = NULL },
+};
+
+static const char *usb_host_hs_utmi_p1_clk_parents[] = {
"init_60m_fclk", "xclk60mhsp1_ck",
};
+#if 0
DEFINE_CLK_MUX(utmi_p1_gfclk, utmi_p1_gfclk_parents, NULL, 0x0,
OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
OMAP4430_CLKSEL_UTMI_P1_SHIFT, OMAP4430_CLKSEL_UTMI_P1_WIDTH,
@@ -1416,11 +1423,25 @@ DEFINE_CLK_MUX(utmi_p1_gfclk, utmi_p1_gfclk_parents, NULL, 0x0,
DEFINE_CLK_GATE(usb_host_hs_utmi_p1_clk, "utmi_p1_gfclk", &utmi_p1_gfclk, 0x0,
OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT, 0x0, NULL);
+#else
+DEFINE_CLK_OMAP_MUX_GATE(usb_host_hs_utmi_p1_clk, "l3_init_clkdm",
+ utmi_p1_clk_sel, OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ OMAP4430_CLKSEL_UTMI_P1_MASK,
+ OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT,
+ NULL, usb_host_hs_utmi_p1_clk_parents, dmic_fck_ops);
+#endif /* #if 0 */
-static const char *utmi_p2_gfclk_parents[] = {
- "init_60m_fclk", "xclk60mhsp2_ck",
+static const struct clksel utmi_p2_clk_sel[] = {
+ { .parent = &init_60m_fclk, .rates = div_1_0_rates },
+ { .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+ { .parent = NULL },
};
+static const char *usb_host_hs_utmi_p2_clk_parents[] = {
+ "init_60m_fclk", "xclk60mhsp2_ck",
+};
+#if 0
DEFINE_CLK_MUX(utmi_p2_gfclk, utmi_p2_gfclk_parents, NULL, 0x0,
OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
OMAP4430_CLKSEL_UTMI_P2_SHIFT, OMAP4430_CLKSEL_UTMI_P2_WIDTH,
@@ -1429,6 +1450,14 @@ DEFINE_CLK_MUX(utmi_p2_gfclk, utmi_p2_gfclk_parents, NULL, 0x0,
DEFINE_CLK_GATE(usb_host_hs_utmi_p2_clk, "utmi_p2_gfclk", &utmi_p2_gfclk, 0x0,
OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT, 0x0, NULL);
+#else
+DEFINE_CLK_OMAP_MUX_GATE(usb_host_hs_utmi_p2_clk, "l3_init_clkdm",
+ utmi_p2_clk_sel, OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ OMAP4430_CLKSEL_UTMI_P2_MASK,
+ OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT,
+ NULL, usb_host_hs_utmi_p2_clk_parents, dmic_fck_ops);
+#endif /* #if 0 */
DEFINE_CLK_GATE(usb_host_hs_utmi_p3_clk, "init_60m_fclk", &init_60m_fclk, 0x0,
OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
@@ -1876,9 +1905,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "uart4_fck", &uart4_fck, CK_443X),
CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X),
CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_443X),
- CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X),
CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_443X),
- CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_443X),
CLK(NULL, "usb_host_hs_utmi_p2_clk", &usb_host_hs_utmi_p2_clk, CK_443X),
CLK(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk, CK_443X),
CLK(NULL, "usb_host_hs_hsic480m_p1_clk", &usb_host_hs_hsic480m_p1_clk, CK_443X),
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 948bcaa82eb6..a285e019ddba 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -286,5 +286,7 @@ extern void omap_reserve(void);
struct omap_hwmod;
extern int omap_dss_reset(struct omap_hwmod *);
+void __init usbhost_init_of(void);
+
#endif /* __ASSEMBLER__ */
#endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 2e44e8a22884..08c663174f75 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -22,6 +22,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <asm/io.h>
@@ -494,6 +496,8 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
usbhs_data.port_mode[i] = pdata->port_mode[i];
+ usbhs_data.clk[i] = pdata->clk[i];
+ usbhs_data.clkrate[i] = pdata->clkrate[i];
usbtll_data.port_mode[i] = pdata->port_mode[i];
ohci_data.port_mode[i] = pdata->port_mode[i];
ehci_data.port_mode[i] = pdata->port_mode[i];
@@ -504,6 +508,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
ohci_data.es2_compatibility = pdata->es2_compatibility;
usbhs_data.ehci_data = &ehci_data;
usbhs_data.ohci_data = &ohci_data;
+ usbhs_data.nports = pdata->nports;
if (cpu_is_omap34xx()) {
setup_ehci_io_mux(pdata->port_mode);
@@ -557,3 +562,74 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
}
#endif
+
+static struct usbhs_omap_board_data bdata;
+
+#define USBHS_NODE "usb-host"
+
+/**
+ * usbhost_init_of - initialize USB Host subsystem from device tree
+ *
+ * Scans the device tree for required information and populates
+ * platform data for the OMAP USB High Speed Host subsystem
+ */
+void __init usbhost_init_of(void)
+{
+ int r;
+ struct device_node *node, *child;
+ int num_ports;
+ int i;
+
+ node = of_find_node_by_name(NULL, USBHS_NODE);
+ if (!node) {
+ pr_err("%s could not find OF node : %s\n",
+ __func__, USBHS_NODE);
+ return;
+ }
+
+ r = of_property_read_u32(node, "num_ports", &num_ports);
+ if (r) {
+ pr_err("%s num_ports not specified in OF node %s\n",
+ __func__, USBHS_NODE);
+ } else {
+ bdata.nports = num_ports;
+ }
+
+ r = of_property_read_bool(node, "phy_reset");
+ bdata.phy_reset = r;
+
+ i = 0;
+ for_each_child_of_node(node, child) {
+ int mode;
+ const char *clk_name;
+ u32 clk_rate;
+
+ r = of_property_read_u32(child, "mode", &mode);
+ if (r) {
+ pr_err("%s mode not specified in OF node %s port %d\n",
+ __func__, USBHS_NODE, i);
+ bdata.port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED;
+ } else {
+ bdata.port_mode[i] = mode;
+ }
+
+ r = of_get_named_gpio(child, "reset_gpio", 0);
+ if (gpio_is_valid(r))
+ bdata.reset_gpio_port[i] = r;
+ else
+ bdata.reset_gpio_port[i] = -EINVAL;
+
+ clk_name = of_get_property(child, "clk", NULL);
+ if (clk_name)
+ bdata.clk[i] = clk_name;
+
+ r = of_property_read_u32(child, "clkrate", &clk_rate);
+ if (!r)
+ bdata.clkrate[i] = clk_rate;
+
+ i++;
+ }
+
+ usbhs_init(&bdata);
+}
+
diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h
index 9b986ead7c45..856ff43a611f 100644
--- a/arch/arm/mach-omap2/usb.h
+++ b/arch/arm/mach-omap2/usb.h
@@ -54,6 +54,7 @@
#define USBPHY_DATA_POLARITY (1 << 23)
struct usbhs_omap_board_data {
+ int nports;
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
/* have to be valid if phy_reset is true and portx is in phy mode */
@@ -69,6 +70,9 @@ struct usbhs_omap_board_data {
* Each PHY can have a separate regulator.
*/
struct regulator *regulator[OMAP3_HS_USB_PORTS];
+
+ const char *clk[OMAP3_HS_USB_PORTS];
+ unsigned long int clkrate[OMAP3_HS_USB_PORTS];
};
extern void usb_musb_init(struct omap_musb_board_data *board_data);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 05164d7f054b..0ddedc71f2fd 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/platform_data/usb-omap.h>
@@ -69,15 +68,14 @@
#define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4)
#define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0)
-#define OMAP4_P1_MODE_CLEAR (3 << 16)
+#define OMAP4_P1_MODE_MASK (3 << 16)
#define OMAP4_P1_MODE_TLL (1 << 16)
#define OMAP4_P1_MODE_HSIC (3 << 16)
-#define OMAP4_P2_MODE_CLEAR (3 << 18)
-#define OMAP4_P2_MODE_TLL (1 << 18)
-#define OMAP4_P2_MODE_HSIC (3 << 18)
#define OMAP_UHH_DEBUG_CSR (0x44)
+#define MAX_HS_USB_PORTS 3 /* Increase this if any chip has more */
+
/* Values of UHH_REVISION - Note: these are not given in the TRM */
#define OMAP_USBHS_REV1 0x00000010 /* OMAP3 */
#define OMAP_USBHS_REV2 0x50700100 /* OMAP4 */
@@ -89,23 +87,27 @@
#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
#define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC)
+struct usbhs_port {
+ struct clk *utmi_clk;
+ struct clk *hsic60m_clk;
+ struct clk *hsic480m_clk;
+ struct clk *aux_clk; /* board dependent clock */
+};
struct usbhs_hcd_omap {
+ int nports;
+ struct usbhs_port port[MAX_HS_USB_PORTS];
+
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
- struct clk *utmi_p1_fck;
- struct clk *usbhost_p1_fck;
- struct clk *utmi_p2_fck;
- struct clk *usbhost_p2_fck;
struct clk *init_60m_fclk;
struct clk *ehci_logic_fck;
void __iomem *uhh_base;
- struct usbhs_omap_platform_data platdata;
+ struct usbhs_omap_platform_data *pdata;
u32 usbhs_rev;
- spinlock_t lock;
};
/*-------------------------------------------------------------------------*/
@@ -194,8 +196,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
int ret;
omap = platform_get_drvdata(pdev);
- ehci_data = omap->platdata.ehci_data;
- ohci_data = omap->platdata.ohci_data;
+ ehci_data = omap->pdata->ehci_data;
+ ohci_data = omap->pdata->ohci_data;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
if (!res) {
@@ -278,31 +280,58 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
static int usbhs_runtime_resume(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
+ int i, r;
dev_dbg(dev, "usbhs_runtime_resume\n");
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
- return -ENODEV;
- }
-
omap_tll_enable();
- spin_lock_irqsave(&omap->lock, flags);
if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
clk_enable(omap->ehci_logic_fck);
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_enable(omap->usbhost_p1_fck);
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_enable(omap->usbhost_p2_fck);
+ for (i = 0; i < omap->nports; i++) {
+ if (omap->port[i].aux_clk) {
+ r = clk_prepare_enable(omap->port[i].aux_clk);
+ if (r) {
+ dev_err(dev,
+ "%s: Can't enable port %d aux clk %d\n",
+ __func__, i, r);
+ }
+ }
- clk_enable(omap->utmi_p1_fck);
- clk_enable(omap->utmi_p2_fck);
+ if (is_ehci_tll_mode(pdata->port_mode[i]) ||
+ is_ehci_hsic_mode(pdata->port_mode[i])) {
+ if (omap->port[i].utmi_clk) {
+ r = clk_enable(omap->port[i].utmi_clk);
+ if (r) {
+ dev_err(dev,
+ "%s: Can't enable port %d clk : %d\n",
+ __func__, i, r);
+ }
+ }
+ }
- spin_unlock_irqrestore(&omap->lock, flags);
+ /* Enable HSIC clocks if required */
+ if (is_ehci_hsic_mode(pdata->port_mode[i])) {
+ if (omap->port[i].hsic60m_clk) {
+ r = clk_enable(omap->port[i].hsic60m_clk);
+ if (r) {
+ dev_err(dev,
+ "%s: Can't enable port %d hsic60m clk : %d\n",
+ __func__, i, r);
+ }
+ }
+ if (omap->port[i].hsic480m_clk) {
+ r = clk_enable(omap->port[i].hsic480m_clk);
+ if (r) {
+ dev_err(dev,
+ "%s: Can't enable port %d hsic480m clk : %d\n",
+ __func__, i, r);
+ }
+ }
+ }
+ }
return 0;
}
@@ -310,30 +339,33 @@ static int usbhs_runtime_resume(struct device *dev)
static int usbhs_runtime_suspend(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
+ int i;
dev_dbg(dev, "usbhs_runtime_suspend\n");
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
- return -ENODEV;
- }
+ for (i = 0; i < omap->nports; i++) {
+ if (is_ehci_tll_mode(pdata->port_mode[i]) ||
+ is_ehci_hsic_mode(pdata->port_mode[i])) {
+ if (omap->port[i].utmi_clk)
+ clk_disable(omap->port[i].utmi_clk);
+ }
- spin_lock_irqsave(&omap->lock, flags);
+ if (is_ehci_hsic_mode(pdata->port_mode[i])) {
+ if (omap->port[i].hsic60m_clk)
+ clk_disable(omap->port[i].hsic60m_clk);
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_disable(omap->usbhost_p1_fck);
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_disable(omap->usbhost_p2_fck);
+ if (omap->port[i].hsic480m_clk)
+ clk_disable(omap->port[i].hsic480m_clk);
+ }
- clk_disable(omap->utmi_p2_fck);
- clk_disable(omap->utmi_p1_fck);
+ if (omap->port[i].aux_clk)
+ clk_disable(omap->port[i].aux_clk);
+ }
if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
clk_disable(omap->ehci_logic_fck);
- spin_unlock_irqrestore(&omap->lock, flags);
omap_tll_disable();
return 0;
@@ -342,9 +374,9 @@ static int usbhs_runtime_suspend(struct device *dev)
static void omap_usbhs_init(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
unsigned reg;
+ int i;
dev_dbg(dev, "starting TI HSUSB Controller\n");
@@ -357,14 +389,15 @@ static void omap_usbhs_init(struct device *dev)
gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[2]))
+ gpio_request_one(pdata->ehci_data->reset_gpio_port[2],
+ GPIOF_OUT_INIT_LOW, "USB3 PHY reset");
+
/* Hold the PHY in RESET for enough time till DIR is high */
udelay(10);
}
pm_runtime_get_sync(dev);
- spin_lock_irqsave(&omap->lock, flags);
- omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
- dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
@@ -407,28 +440,21 @@ static void omap_usbhs_init(struct device *dev)
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
}
} else if (is_omap_usbhs_rev2(omap)) {
- /* Clear port mode fields for PHY mode*/
- reg &= ~OMAP4_P1_MODE_CLEAR;
- reg &= ~OMAP4_P2_MODE_CLEAR;
-
- if (is_ehci_tll_mode(pdata->port_mode[0]) ||
- (is_ohci_port(pdata->port_mode[0])))
- reg |= OMAP4_P1_MODE_TLL;
- else if (is_ehci_hsic_mode(pdata->port_mode[0]))
- reg |= OMAP4_P1_MODE_HSIC;
-
- if (is_ehci_tll_mode(pdata->port_mode[1]) ||
- (is_ohci_port(pdata->port_mode[1])))
- reg |= OMAP4_P2_MODE_TLL;
- else if (is_ehci_hsic_mode(pdata->port_mode[1]))
- reg |= OMAP4_P2_MODE_HSIC;
+ for (i = 0; i < omap->nports; i++) {
+ /* Clear port mode fields for PHY mode*/
+ reg &= ~(OMAP4_P1_MODE_MASK << 2*i);
+
+ if (is_ehci_tll_mode(pdata->port_mode[i]) ||
+ (is_ohci_port(pdata->port_mode[i])))
+ reg |= OMAP4_P1_MODE_TLL << 2*i;
+ else if (is_ehci_hsic_mode(pdata->port_mode[i]))
+ reg |= OMAP4_P1_MODE_HSIC << 2*i;
+ }
}
usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
- spin_unlock_irqrestore(&omap->lock, flags);
-
pm_runtime_put_sync(dev);
if (pdata->ehci_data->phy_reset) {
/* Hold the PHY in RESET for enough time till
@@ -443,13 +469,17 @@ static void omap_usbhs_init(struct device *dev)
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_set_value_cansleep
(pdata->ehci_data->reset_gpio_port[1], 1);
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[2]))
+ gpio_set_value_cansleep
+ (pdata->ehci_data->reset_gpio_port[2], 1);
}
}
static void omap_usbhs_deinit(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
@@ -457,6 +487,9 @@ static void omap_usbhs_deinit(struct device *dev)
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[2]))
+ gpio_free(pdata->ehci_data->reset_gpio_port[2]);
}
}
@@ -474,101 +507,176 @@ static int usbhs_omap_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0;
int i;
+ bool need_logic_fck;
if (!pdata) {
dev_err(dev, "Missing platform data\n");
- ret = -ENOMEM;
- goto end_probe;
+ return -ENODEV;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
+ if (!res) {
+ dev_err(dev, "UHH EHCI get resource failed\n");
+ return -ENODEV;
}
omap = kzalloc(sizeof(*omap), GFP_KERNEL);
if (!omap) {
dev_err(dev, "Memory allocation failed\n");
- ret = -ENOMEM;
- goto end_probe;
+ return -ENOMEM;
}
- spin_lock_init(&omap->lock);
-
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- omap->platdata.port_mode[i] = pdata->port_mode[i];
-
- omap->platdata.ehci_data = pdata->ehci_data;
- omap->platdata.ohci_data = pdata->ohci_data;
+ omap->uhh_base = ioremap(res->start, resource_size(res));
+ if (!omap->uhh_base) {
+ dev_err(dev, "UHH ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_remap;
+ }
+ omap->pdata = pdata;
+ platform_set_drvdata(pdev, omap);
pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
- is_ehci_hsic_mode(i)) {
- omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
- if (IS_ERR(omap->ehci_logic_fck)) {
- ret = PTR_ERR(omap->ehci_logic_fck);
- dev_warn(dev, "ehci_logic_fck failed:%d\n",
- ret);
- }
+ /* we need to call runtime suspend before we update omap->nports
+ * to prevent unbalanced clk_disable()
+ */
+ pm_runtime_put_sync(dev);
+
+ /*
+ * If platform data contains nports then use that
+ * else make out number of ports from USBHS revision
+ */
+ if (pdata->nports) {
+ if (omap->nports > MAX_HS_USB_PORTS) {
+ dev_err(dev,
+ "Platform data says %d ports but MAX_HS_USB_PORTS is %d\n",
+ omap->nports, MAX_HS_USB_PORTS);
+ } else {
+ omap->nports = pdata->nports;
+ }
+ } else {
+ switch (omap->usbhs_rev) {
+ case OMAP_USBHS_REV1:
+ omap->nports = 3;
+ break;
+ case OMAP_USBHS_REV2:
+ /* Both OMAP4 and 5 show the same revision but they have
+ * different number of ports i.e. 2 and 3 respectively.
+ * OMAP5 platforms must supply nports via platform data.
+ */
+ omap->nports = 2;
+ break;
+ default:
+ omap->nports = MAX_HS_USB_PORTS;
+ dev_info(dev,
+ "USB HOST Rev:0x%d not recognized, assuming %d ports\n",
+ omap->usbhs_rev, omap->nports);
break;
}
+ }
- omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
- if (IS_ERR(omap->utmi_p1_fck)) {
- ret = PTR_ERR(omap->utmi_p1_fck);
- dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
- goto err_end;
+ need_logic_fck = false;
+ for (i = 0; i < omap->nports; i++) {
+ if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
+ is_ehci_hsic_mode(i))
+ need_logic_fck |= true;
+ }
+
+ if (need_logic_fck) {
+ omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
+ if (IS_ERR(omap->ehci_logic_fck)) {
+ ret = PTR_ERR(omap->ehci_logic_fck);
+ dev_warn(dev, "ehci_logic_fck failed:%d\n", ret);
+ }
}
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
if (IS_ERR(omap->xclk60mhsp1_ck)) {
ret = PTR_ERR(omap->xclk60mhsp1_ck);
dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
- goto err_utmi_p1_fck;
- }
-
- omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
- if (IS_ERR(omap->utmi_p2_fck)) {
- ret = PTR_ERR(omap->utmi_p2_fck);
- dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
- goto err_xclk60mhsp1_ck;
+ goto err_xclk60mhsp1;
}
omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
if (IS_ERR(omap->xclk60mhsp2_ck)) {
ret = PTR_ERR(omap->xclk60mhsp2_ck);
dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
- goto err_utmi_p2_fck;
- }
-
- omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
- if (IS_ERR(omap->usbhost_p1_fck)) {
- ret = PTR_ERR(omap->usbhost_p1_fck);
- dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
- goto err_xclk60mhsp2_ck;
- }
-
- omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
- if (IS_ERR(omap->usbhost_p2_fck)) {
- ret = PTR_ERR(omap->usbhost_p2_fck);
- dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
- goto err_usbhost_p1_fck;
+ goto err_xclk60mhsp2;
}
omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
if (IS_ERR(omap->init_60m_fclk)) {
ret = PTR_ERR(omap->init_60m_fclk);
dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
- goto err_usbhost_p2_fck;
+ goto err_init60m;
+ }
+
+ for (i = 0; i < omap->nports; i++) {
+ struct clk *pclk;
+ char utmi_clk[] = "usb_host_hs_utmi_px_clk";
+ char hsic_clk[] = "usb_host_hs_hsic480m_px_clk";
+
+ /* clock names are indexed from 1*/
+ sprintf(utmi_clk, "usb_host_hs_utmi_p%d_clk", i + 1);
+
+ /* If a clock is not found we won't bail out as not all
+ * platforms have all clocks and we can function without
+ * them
+ */
+ pclk = clk_get(dev, utmi_clk);
+ if (IS_ERR(pclk))
+ dev_err(dev, "Failed to get clock : %s : %ld\n",
+ utmi_clk, PTR_ERR(pclk));
+ else
+ omap->port[i].utmi_clk = pclk;
+
+ sprintf(hsic_clk, "usb_host_hs_hsic480m_p%d_clk", i + 1);
+ pclk = clk_get(dev, hsic_clk);
+ if (IS_ERR(pclk))
+ dev_err(dev, "Failed to get clock : %s : %ld\n",
+ hsic_clk, PTR_ERR(pclk));
+ else
+ omap->port[i].hsic480m_clk = pclk;
+
+ sprintf(hsic_clk, "usb_host_hs_hsic60m_p%d_clk", i + 1);
+ pclk = clk_get(dev, hsic_clk);
+ if (IS_ERR(pclk))
+ dev_err(dev, "Failed to get clock : %s : %ld\n",
+ hsic_clk, PTR_ERR(pclk));
+ else
+ omap->port[i].hsic60m_clk = pclk;
+
+ /* get the auxiliary clock if required and set its rate */
+ if (pdata->clk[i] && pdata->clkrate[i]) {
+ pclk = clk_get(dev, pdata->clk[i]);
+ if (IS_ERR(pclk)) {
+ dev_err(dev,
+ "Failed to get clock %s\n", pdata->clk[i]);
+ } else {
+ omap->port[i].aux_clk = pclk;
+
+ ret = clk_set_rate(pclk, pdata->clkrate[i]);
+ if (ret) {
+ dev_err(dev,
+ "Failed to set clock %s to %luHz\n",
+ pdata->clk[i], pdata->clkrate[i]);
+ }
+ }
+ }
}
if (is_ehci_phy_mode(pdata->port_mode[0])) {
/* for OMAP3 , the clk set paretn fails */
- ret = clk_set_parent(omap->utmi_p1_fck,
+ ret = clk_set_parent(omap->port[0].utmi_clk,
omap->xclk60mhsp1_ck);
if (ret != 0)
dev_err(dev, "xclk60mhsp1_ck set parent"
"failed error:%d\n", ret);
} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
- ret = clk_set_parent(omap->utmi_p1_fck,
+ ret = clk_set_parent(omap->port[0].utmi_clk,
omap->init_60m_fclk);
if (ret != 0)
dev_err(dev, "init_60m_fclk set parent"
@@ -576,34 +684,19 @@ static int usbhs_omap_probe(struct platform_device *pdev)
}
if (is_ehci_phy_mode(pdata->port_mode[1])) {
- ret = clk_set_parent(omap->utmi_p2_fck,
+ ret = clk_set_parent(omap->port[1].utmi_clk,
omap->xclk60mhsp2_ck);
if (ret != 0)
dev_err(dev, "xclk60mhsp2_ck set parent"
"failed error:%d\n", ret);
} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
- ret = clk_set_parent(omap->utmi_p2_fck,
+ ret = clk_set_parent(omap->port[1].utmi_clk,
omap->init_60m_fclk);
if (ret != 0)
dev_err(dev, "init_60m_fclk set parent"
"failed error:%d\n", ret);
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
- if (!res) {
- dev_err(dev, "UHH EHCI get resource failed\n");
- ret = -ENODEV;
- goto err_init_60m_fclk;
- }
-
- omap->uhh_base = ioremap(res->start, resource_size(res));
- if (!omap->uhh_base) {
- dev_err(dev, "UHH ioremap failed\n");
- ret = -ENOMEM;
- goto err_init_60m_fclk;
- }
-
- platform_set_drvdata(pdev, omap);
omap_usbhs_init(dev);
ret = omap_usbhs_alloc_children(pdev);
@@ -612,39 +705,36 @@ static int usbhs_omap_probe(struct platform_device *pdev)
goto err_alloc;
}
- goto end_probe;
+ pr_info("OMAP USB HOST : revision 0x%x, ports %d\n",
+ omap->usbhs_rev, omap->nports);
+ return 0;
err_alloc:
omap_usbhs_deinit(&pdev->dev);
iounmap(omap->uhh_base);
-err_init_60m_fclk:
- clk_put(omap->init_60m_fclk);
-
-err_usbhost_p2_fck:
- clk_put(omap->usbhost_p2_fck);
+ for (i = 0; i < omap->nports; i++) {
+ clk_put(omap->port[i].utmi_clk);
+ clk_put(omap->port[i].hsic60m_clk);
+ clk_put(omap->port[i].hsic480m_clk);
+ clk_put(omap->port[i].aux_clk);
+ }
-err_usbhost_p1_fck:
- clk_put(omap->usbhost_p1_fck);
+ clk_put(omap->init_60m_fclk);
-err_xclk60mhsp2_ck:
+err_init60m:
clk_put(omap->xclk60mhsp2_ck);
-err_utmi_p2_fck:
- clk_put(omap->utmi_p2_fck);
-
-err_xclk60mhsp1_ck:
+err_xclk60mhsp2:
clk_put(omap->xclk60mhsp1_ck);
-err_utmi_p1_fck:
- clk_put(omap->utmi_p1_fck);
-
-err_end:
+err_xclk60mhsp1:
clk_put(omap->ehci_logic_fck);
+
pm_runtime_disable(dev);
- kfree(omap);
-end_probe:
+err_remap:
+ kfree(omap);
return ret;
}
@@ -657,18 +747,24 @@ end_probe:
static int usbhs_omap_remove(struct platform_device *pdev)
{
struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
+ int i;
omap_usbhs_deinit(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
iounmap(omap->uhh_base);
+
+ for (i = 0; i < omap->nports; i++) {
+ clk_put(omap->port[i].utmi_clk);
+ clk_put(omap->port[i].hsic60m_clk);
+ clk_put(omap->port[i].hsic480m_clk);
+ clk_put(omap->port[i].aux_clk);
+ }
+
clk_put(omap->init_60m_fclk);
- clk_put(omap->usbhost_p2_fck);
- clk_put(omap->usbhost_p1_fck);
clk_put(omap->xclk60mhsp2_ck);
- clk_put(omap->utmi_p2_fck);
clk_put(omap->xclk60mhsp1_ck);
- clk_put(omap->utmi_p1_fck);
clk_put(omap->ehci_logic_fck);
- pm_runtime_disable(&pdev->dev);
+
kfree(omap);
return 0;
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c
index eb869153206d..328bf05f80d5 100644
--- a/drivers/mfd/omap-usb-tll.c
+++ b/drivers/mfd/omap-usb-tll.c
@@ -54,10 +54,13 @@
#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
+#define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16)
+#define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15)
#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10)
#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9)
#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8)
+#define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI (2 << 1)
#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
@@ -82,8 +85,12 @@
#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num)
#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num)
-#define OMAP_REV2_TLL_CHANNEL_COUNT 2
-#define OMAP_TLL_CHANNEL_COUNT 3
+#define REV2_TLL_CHANNEL_COUNT 2
+#define DEFAULT_TLL_CHANNEL_COUNT 3
+
+/* Update if any chip has more */
+#define MAX_TLL_CHANNEL_COUNT 3
+
#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0)
#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1)
#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2)
@@ -92,21 +99,27 @@
#define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */
#define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */
#define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */
+#define OMAP_USBTLL_REV4 0x6 /* OMAP5 */
#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
+/* only PHY and UNUSED modes don't need TLL */
+#define mode_needs_tll(x) ((x != OMAP_USBHS_PORT_MODE_UNUSED) && \
+ (x != OMAP_EHCI_PORT_MODE_PHY))
+
struct usbtll_omap {
- struct clk *usbtll_p1_fck;
- struct clk *usbtll_p2_fck;
- struct usbtll_omap_platform_data platdata;
+ void __iomem *base;
+ int nch; /* number of channels */
+ struct clk *ch_clk[MAX_TLL_CHANNEL_COUNT];
+ struct usbtll_omap_platform_data *pdata;
/* secure the register updates */
spinlock_t lock;
};
/*-------------------------------------------------------------------------*/
-const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
-struct platform_device *tll_pdev;
+static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
+static struct device *tll_dev;
/*-------------------------------------------------------------------------*/
@@ -208,79 +221,84 @@ static int usbtll_omap_probe(struct platform_device *pdev)
struct resource *res;
struct usbtll_omap *tll;
unsigned reg;
- unsigned long flags;
int ret = 0;
- int i, ver, count;
+ int i, ver;
+ bool needs_tll;
dev_dbg(dev, "starting TI HSUSB TLL Controller\n");
tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL);
if (!tll) {
dev_err(dev, "Memory allocation failed\n");
- ret = -ENOMEM;
- goto end;
+ return -ENOMEM;
}
- spin_lock_init(&tll->lock);
-
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- tll->platdata.port_mode[i] = pdata->port_mode[i];
-
- tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
- if (IS_ERR(tll->usbtll_p1_fck)) {
- ret = PTR_ERR(tll->usbtll_p1_fck);
- dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
- goto err_tll;
+ if (!pdata) {
+ dev_err(dev, "%s : Platform data mising\n", __func__);
+ return -ENODEV;
}
- tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
- if (IS_ERR(tll->usbtll_p2_fck)) {
- ret = PTR_ERR(tll->usbtll_p2_fck);
- dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
- goto err_usbtll_p1_fck;
- }
+ spin_lock_init(&tll->lock);
+
+ tll->pdata = pdata;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "usb tll get resource failed\n");
ret = -ENODEV;
- goto err_usbtll_p2_fck;
+ goto err_mem;
}
base = ioremap(res->start, resource_size(res));
if (!base) {
dev_err(dev, "TLL ioremap failed\n");
ret = -ENOMEM;
- goto err_usbtll_p2_fck;
+ goto err_mem;
}
+ tll->base = base;
platform_set_drvdata(pdev, tll);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- spin_lock_irqsave(&tll->lock, flags);
-
ver = usbtll_read(base, OMAP_USBTLL_REVISION);
switch (ver) {
case OMAP_USBTLL_REV1:
- case OMAP_USBTLL_REV2:
- count = OMAP_TLL_CHANNEL_COUNT;
+ case OMAP_USBTLL_REV4:
+ tll->nch = DEFAULT_TLL_CHANNEL_COUNT;
break;
+ case OMAP_USBTLL_REV2:
case OMAP_USBTLL_REV3:
- count = OMAP_REV2_TLL_CHANNEL_COUNT;
+ tll->nch = REV2_TLL_CHANNEL_COUNT;
break;
default:
- dev_err(dev, "TLL version failed\n");
- ret = -ENODEV;
- goto err_ioremap;
+ tll->nch = DEFAULT_TLL_CHANNEL_COUNT;
+ dev_info(dev,
+ "USB TLL Rev : 0x%x not recognized, assuming %d channels\n",
+ ver, tll->nch);
+ break;
}
- if (is_ehci_tll_mode(pdata->port_mode[0]) ||
- is_ehci_tll_mode(pdata->port_mode[1]) ||
- is_ehci_tll_mode(pdata->port_mode[2]) ||
- is_ohci_port(pdata->port_mode[0]) ||
- is_ohci_port(pdata->port_mode[1]) ||
- is_ohci_port(pdata->port_mode[2])) {
+ for (i = 0; i < tll->nch; i++) {
+ char clk_name[] = "usb_tll_hs_usb_chx_clk";
+ struct clk *fck;
+
+ sprintf(clk_name, "usb_tll_hs_usb_ch%d_clk", i);
+ fck = clk_get(dev, clk_name);
+
+ if (IS_ERR(fck)) {
+ dev_err(dev, "can't get clock : %s\n", clk_name);
+ ret = PTR_ERR(fck);
+ goto err_clk;
+ }
+ tll->ch_clk[i] = fck;
+ }
+
+ needs_tll = false;
+ for (i = 0; i < tll->nch; i++)
+ needs_tll |= mode_needs_tll(pdata->port_mode[i]);
+
+ if (needs_tll) {
/* Program Common TLL register */
reg = usbtll_read(base, OMAP_TLL_SHARED_CONF);
@@ -292,7 +310,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
usbtll_write(base, OMAP_TLL_SHARED_CONF, reg);
/* Enable channels now */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < tll->nch; i++) {
reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i));
if (is_ohci_port(pdata->port_mode[i])) {
@@ -308,6 +326,15 @@ static int usbtll_omap_probe(struct platform_device *pdev)
reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
+ } else if (pdata->port_mode[i] ==
+ OMAP_EHCI_PORT_MODE_HSIC) {
+ /*
+ * HSIC Mode requires UTMI port configurations
+ */
+ reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS
+ | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
+ | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI
+ | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
} else {
continue;
}
@@ -320,25 +347,25 @@ static int usbtll_omap_probe(struct platform_device *pdev)
}
}
-err_ioremap:
- spin_unlock_irqrestore(&tll->lock, flags);
- iounmap(base);
- pm_runtime_put_sync(dev);
- tll_pdev = pdev;
- if (!ret)
- goto end;
- pm_runtime_disable(dev);
+ /* only after this can omap_tll_enable/disable work */
+ tll_dev = dev;
-err_usbtll_p2_fck:
- clk_put(tll->usbtll_p2_fck);
+err_clk:
+ for (--i; i >= 0 ; i--)
+ clk_put(tll->ch_clk[i]);
+
+ pm_runtime_put_sync(dev);
+ if (ret == 0) {
+ pr_info("OMAP USB TLL : revision 0x%x, channels %d\n",
+ ver, tll->nch);
+ return 0;
+ }
-err_usbtll_p1_fck:
- clk_put(tll->usbtll_p1_fck);
+ iounmap(base);
+ pm_runtime_disable(dev);
-err_tll:
+err_mem:
kfree(tll);
-
-end:
return ret;
}
@@ -351,99 +378,83 @@ end:
static int usbtll_omap_remove(struct platform_device *pdev)
{
struct usbtll_omap *tll = platform_get_drvdata(pdev);
+ int i;
+
+ tll_dev = NULL;
+ iounmap(tll->base);
+ for (i = 0; i < tll->nch; i++)
+ clk_put(tll->ch_clk[i]);
- clk_put(tll->usbtll_p2_fck);
- clk_put(tll->usbtll_p1_fck);
pm_runtime_disable(&pdev->dev);
kfree(tll);
return 0;
}
-static int usbtll_runtime_resume(struct device *dev)
+static struct platform_driver usbtll_omap_driver = {
+ .driver = {
+ .name = (char *)usbtll_driver_name,
+ .owner = THIS_MODULE,
+ },
+ .probe = usbtll_omap_probe,
+ .remove = usbtll_omap_remove,
+};
+
+int omap_tll_enable(void)
{
- struct usbtll_omap *tll = dev_get_drvdata(dev);
- struct usbtll_omap_platform_data *pdata = &tll->platdata;
+ struct usbtll_omap *tll;
unsigned long flags;
+ int i;
- dev_dbg(dev, "usbtll_runtime_resume\n");
-
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
+ if (!tll_dev) {
+ pr_err("%s: OMAP USB TLL not initialized\n", __func__);
return -ENODEV;
}
+ tll = dev_get_drvdata(tll_dev);
spin_lock_irqsave(&tll->lock, flags);
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_enable(tll->usbtll_p1_fck);
-
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_enable(tll->usbtll_p2_fck);
+ for (i = 0; i < tll->nch; i++) {
+ if (mode_needs_tll(tll->pdata->port_mode[i])) {
+ int r;
+ r = clk_enable(tll->ch_clk[i]);
+ if (r) {
+ dev_err(tll_dev,
+ "%s : Error enabling ch %d clock: %d\n",
+ __func__, i, r);
+ }
+ }
+ }
+ i = pm_runtime_get_sync(tll_dev);
spin_unlock_irqrestore(&tll->lock, flags);
- return 0;
+ return i;
}
+EXPORT_SYMBOL_GPL(omap_tll_enable);
-static int usbtll_runtime_suspend(struct device *dev)
+int omap_tll_disable(void)
{
- struct usbtll_omap *tll = dev_get_drvdata(dev);
- struct usbtll_omap_platform_data *pdata = &tll->platdata;
+ struct usbtll_omap *tll;
unsigned long flags;
+ int i;
- dev_dbg(dev, "usbtll_runtime_suspend\n");
-
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
+ if (!tll_dev) {
+ pr_err("%s: OMAP USB TLL not initialized\n", __func__);
return -ENODEV;
}
+ tll = dev_get_drvdata(tll_dev);
spin_lock_irqsave(&tll->lock, flags);
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_disable(tll->usbtll_p1_fck);
-
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_disable(tll->usbtll_p2_fck);
+ for (i = 0; i < tll->nch; i++) {
+ if (mode_needs_tll(tll->pdata->port_mode[i]))
+ clk_disable(tll->ch_clk[i]);
+ }
+ i = pm_runtime_put_sync(tll_dev);
spin_unlock_irqrestore(&tll->lock, flags);
- return 0;
-}
-
-static const struct dev_pm_ops usbtllomap_dev_pm_ops = {
- SET_RUNTIME_PM_OPS(usbtll_runtime_suspend,
- usbtll_runtime_resume,
- NULL)
-};
-
-static struct platform_driver usbtll_omap_driver = {
- .driver = {
- .name = (char *)usbtll_driver_name,
- .owner = THIS_MODULE,
- .pm = &usbtllomap_dev_pm_ops,
- },
- .probe = usbtll_omap_probe,
- .remove = usbtll_omap_remove,
-};
-
-int omap_tll_enable(void)
-{
- if (!tll_pdev) {
- pr_err("missing omap usbhs tll platform_data\n");
- return -ENODEV;
- }
- return pm_runtime_get_sync(&tll_pdev->dev);
-}
-EXPORT_SYMBOL_GPL(omap_tll_enable);
-
-int omap_tll_disable(void)
-{
- if (!tll_pdev) {
- pr_err("missing omap usbhs tll platform_data\n");
- return -ENODEV;
- }
- return pm_runtime_put_sync(&tll_pdev->dev);
+ return i;
}
EXPORT_SYMBOL_GPL(omap_tll_disable);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index e5c03b534fae..0af15854fb4f 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -53,6 +53,7 @@ of_get_fixed_voltage_config(struct device *dev)
struct device_node *np = dev->of_node;
const __be32 *delay;
struct regulator_init_data *init_data;
+ const char *vin_name;
config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
GFP_KERNEL);
@@ -102,8 +103,9 @@ of_get_fixed_voltage_config(struct device *dev)
if (of_find_property(np, "gpio-open-drain", NULL))
config->gpio_is_open_drain = true;
- if (of_find_property(np, "vin-supply", NULL))
- config->input_supply = "vin";
+ vin_name = of_get_property(np, "vin-supply", NULL);
+ if (vin_name)
+ config->input_supply = vin_name;
return config;
}
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index ac17a7c3a0cd..8c3a492ac18b 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -72,37 +72,6 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
return __raw_readl(base + reg);
}
-
-static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(1000);
- unsigned reg = 0;
-
- reg = ULPI_FUNC_CTRL_RESET
- /* FUNCTION_CTRL_SET register */
- | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
- /* Write */
- | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
- /* PORTn */
- | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
- /* start ULPI access*/
- | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
-
- ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg);
-
- /* Wait for ULPI access completion */
- while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI)
- & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- dev_dbg(hcd->self.controller,
- "phy reset operation timed out\n");
- break;
- }
- }
-}
-
static int omap_ehci_init(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -111,42 +80,11 @@ static int omap_ehci_init(struct usb_hcd *hcd)
pdata = hcd->self.controller->platform_data;
- /* Hold PHYs in reset while initializing EHCI controller */
- if (pdata->phy_reset) {
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
-
- /* Hold the PHY in RESET for enough time till DIR is high */
- udelay(10);
- }
-
- /* Soft reset the PHY using PHY reset command over ULPI */
- if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(hcd, 0);
- if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(hcd, 1);
-
/* we know this is the memory we want, no need to ioremap again */
ehci->caps = hcd->regs;
rc = ehci_setup(hcd);
- if (pdata->phy_reset) {
- /* Hold the PHY in RESET for enough time till
- * PHY is settled and ready
- */
- udelay(10);
-
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
- }
-
return rc;
}
@@ -241,6 +179,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
}
}
+ /* Hold PHYs in reset while initializing EHCI controller */
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[2]))
+ gpio_set_value_cansleep(pdata->reset_gpio_port[2], 0);
+
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ udelay(10);
+ }
+
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -262,6 +215,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
goto err_pm_runtime;
}
+ if (pdata->phy_reset) {
+ /* Hold the PHY in RESET for enough time till
+ * PHY is settled and ready
+ */
+ udelay(10);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[2]))
+ gpio_set_value_cansleep(pdata->reset_gpio_port[2], 1);
+ }
return 0;
@@ -288,7 +256,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd_omap_platform_data *pdata = dev->platform_data;
usb_remove_hcd(hcd);
disable_put_regulator(dev->platform_data);
@@ -298,13 +265,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
- if (pdata->phy_reset) {
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_free(pdata->reset_gpio_port[0]);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_free(pdata->reset_gpio_port[1]);
- }
return 0;
}
diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h
index ef65b67c56c3..ee85334aa990 100644
--- a/include/linux/platform_data/usb-omap.h
+++ b/include/linux/platform_data/usb-omap.h
@@ -55,11 +55,15 @@ struct ohci_hcd_omap_platform_data {
};
struct usbhs_omap_platform_data {
+ int nports;
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
struct ehci_hcd_omap_platform_data *ehci_data;
struct ohci_hcd_omap_platform_data *ohci_data;
+ const char *clk[OMAP3_HS_USB_PORTS];
+ unsigned long int clkrate[OMAP3_HS_USB_PORTS];
+
/* OMAP3 <= ES2.1 have a single ulpi bypass control bit */
unsigned single_ulpi_bypass:1;
};