2013-05-16 14:21:56

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 0/8] Tegra USB PHY driver series

delta from v3:
This patch series is prepared as follow up of TEGRA USB PHY driver patch series
discussed at: https://lkml.org/lkml/2013/5/10/241

Venu Byravarasu (8):
ARM: tegra: finalize USB EHCI and PHY bindings
arm: dt: Tegra20: Modify ULPI reset GPIO properties
ARM: tegra: update device trees for USB binding rework
usb: phy: tegra: Return correct error value provided by clk_get_sys
usb: phy: tegra: Get PHY mode using DT
usb: phy: tegra: get ULPI reset GPIO info using DT.
usb: phy: tegra: Add error handling & clean up.
usb: phy: registering Tegra USB PHY as platform driver

.../bindings/usb/nvidia,tegra20-ehci.txt | 27 +--
.../bindings/usb/nvidia,tegra20-usb-phy.txt | 41 +++-
arch/arm/boot/dts/tegra20-colibri-512.dtsi | 6 +-
arch/arm/boot/dts/tegra20-harmony.dts | 15 +-
arch/arm/boot/dts/tegra20-iris-512.dts | 9 +-
arch/arm/boot/dts/tegra20-paz00.dts | 15 +-
arch/arm/boot/dts/tegra20-seaboard.dts | 26 ++-
arch/arm/boot/dts/tegra20-tamonten.dtsi | 4 +
arch/arm/boot/dts/tegra20-trimslice.dts | 25 ++-
arch/arm/boot/dts/tegra20-ventana.dts | 15 +-
arch/arm/boot/dts/tegra20-whistler.dts | 28 ++
arch/arm/boot/dts/tegra20.dtsi | 49 +++-
drivers/usb/host/ehci-tegra.c | 105 +++----
drivers/usb/phy/phy-tegra-usb.c | 318 ++++++++++++--------
include/linux/usb/tegra_usb_phy.h | 13 +-
15 files changed, 451 insertions(+), 245 deletions(-)


2013-05-16 14:22:06

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 1/8] ARM: tegra: finalize USB EHCI and PHY bindings

The existing Tegra USB bindings have a few issues:

1) Many properties are documented as being part of the EHCI controller
node, yet they apply more to the PHY device. They should be moved.

2) Some registers in PHY1 are shared with PHY3, and hence PHY3 needs a
reg entry to point at PHY1's register space. We can't assume the PHY1
driver is present, so the PHY3 driver will directly access those
registers.

3) The list of clocks required by the PHY was missing some required
entries.

4) UTMI PHY Timing parameters are added

5) VBUS control is now specified using a regulator rather than a plain GPIO

6) Added nvidia,is-wired property to indicate whether the device is
hard wired on the board, or pluggable.

This patch fixes the binding definition to resolve these issues.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v3:
Added a blank line at EOF of nvidia,tegra20-usb-phy.txt.

delta from v2:
Moved vbus-supply under "Required properties for dr_mode == otg" heading.

delta from v1:
1. added UTMI PHY timing params.
2. replaced gadget with peripheral in dr_mode
3. added nvidia,is-wired & vbus-supply params.


.../bindings/usb/nvidia,tegra20-ehci.txt | 27 ++----------
.../bindings/usb/nvidia,tegra20-usb-phy.txt | 41 ++++++++++++++++++-
2 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
index 34c9528..df09330 100644
--- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
@@ -6,27 +6,10 @@ Practice : Universal Serial Bus" with the following modifications
and additions :

Required properties :
- - compatible : Should be "nvidia,tegra20-ehci" for USB controllers
- used in host mode.
- - phy_type : Should be one of "ulpi" or "utmi".
- - nvidia,vbus-gpio : If present, specifies a gpio that needs to be
- activated for the bus to be powered.
- - nvidia,phy : phandle of the PHY instance, the controller is connected to.
-
-Required properties for phy_type == ulpi:
- - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
+ - compatible : Should be "nvidia,tegra20-ehci".
+ - nvidia,phy : phandle of the PHY that the controller is connected to.
+ - clocks : Contains a single entry which defines the USB controller's clock.

Optional properties:
- - dr_mode : dual role mode. Indicates the working mode for
- nvidia,tegra20-ehci compatible controllers. Can be "host", "peripheral",
- or "otg". Default to "host" if not defined for backward compatibility.
- host means this is a host controller
- peripheral means it is device controller
- otg means it can operate as either ("on the go")
- - nvidia,has-legacy-mode : boolean indicates whether this controller can
- operate in legacy mode (as APX 2500 / 2600). In legacy mode some
- registers are accessed through the APB_MISC base address instead of
- the USB controller. Since this is a legacy issue it probably does not
- warrant a compatible string of its own.
- - nvidia,needs-double-reset : boolean is to be set for some of the Tegra2
- USB ports, which need reset twice due to hardware issues.
+ - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20
+ USB ports, which need reset twice due to hardware issues.
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
index 6bdaba2..c4c9e9e 100644
--- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
@@ -4,14 +4,49 @@ The device node for Tegra SOC USB PHY:

Required properties :
- compatible : Should be "nvidia,tegra20-usb-phy".
- - reg : Address and length of the register set for the USB PHY interface.
- - phy_type : Should be one of "ulpi" or "utmi".
+ - reg : Defines the following set of registers, in the order listed:
+ - The PHY's own register set.
+ Always present.
+ - The register set of the PHY containing the UTMI pad control registers.
+ Present if-and-only-if phy_type == utmi.
+ - phy_type : Should be one of "utmi", "ulpi" or "hsic".
+ - clocks : Defines the clocks listed in the clock-names property.
+ - clock-names : The following clock names must be present:
+ - reg: The clock needed to access the PHY's own registers. This is the
+ associated EHCI controller's clock. Always present.
+ - pll_u: PLL_U. Always present.
+ - timer: The timeout clock (clk_m). Present if phy_type == utmi.
+ - utmi-pads: The clock needed to access the UTMI pad control registers.
+ Present if phy_type == utmi.
+ - ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2).
+ Present if phy_type == ulpi, and ULPI link mode is in use.

Required properties for phy_type == ulpi:
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.

+Required PHY timing params for utmi phy:
+ - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
+ start of sync launches RxActive
+ - nvidia,elastic-limit : Variable FIFO Depth of elastic input store
+ - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
+ before declare IDLE.
+ - nvidia,term-range-adj : Range adjusment on terminations
+ - nvidia,xcvr-setup : HS driver output control
+ - nvidia,xcvr-lsfslew : LS falling slew rate control.
+ - nvidia,xcvr-lsrslew : LS rising slew rate control.
+
Optional properties:
- nvidia,has-legacy-mode : boolean indicates whether this controller can
operate in legacy mode (as APX 2500 / 2600). In legacy mode some
registers are accessed through the APB_MISC base address instead of
- the USB controller.
\ No newline at end of file
+ the USB controller.
+ - nvidia,is-wired : boolean. Indicates whether we can do certain kind of power
+ optimizations for the devices that are always connected. e.g. modem.
+ - dr_mode : dual role mode. Indicates the working mode for the PHY. Can be
+ "host", "peripheral", or "otg". Defaults to "host" if not defined.
+ host means this is a host controller
+ peripheral means it is device controller
+ otg means it can operate as either ("on the go")
+
+Required properties for dr_mode == otg:
+ - vbus-supply: regulator for VBUS
--
1.7.0.4

2013-05-16 14:22:20

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 3/8] ARM: tegra: update device trees for USB binding rework

This patch updates all Tegra board files so that they contain all the
properties required by the updated USB DT binding. Note that this patch
only adds the new properties and does not yet remove the old properties,
in order to maintain bisectability. The old properties will be removed
once the driver has been updated to assume the new bindings.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v3:
Added status field to USB PHY DT nodes.

delta from v2:
1. Removed dr_mode setting to otg, due to lack of knowledge of all Vbus supplies,
on all target platforms.

2. All changes related to 'nvidia,phy-reset-gpio' were moved to patch 2 of the
same series.

delta from v1:
1. Fixed voltage regulators were used for vbus-supply
2. Added UTMI PHY timing Parameters to DT.

arch/arm/boot/dts/tegra20-harmony.dts | 9 ++++++
arch/arm/boot/dts/tegra20-iris-512.dts | 9 +++++-
arch/arm/boot/dts/tegra20-paz00.dts | 9 ++++++
arch/arm/boot/dts/tegra20-seaboard.dts | 20 ++++++++++++
arch/arm/boot/dts/tegra20-tamonten.dtsi | 4 ++
arch/arm/boot/dts/tegra20-trimslice.dts | 19 ++++++++++++
arch/arm/boot/dts/tegra20-ventana.dts | 9 ++++++
arch/arm/boot/dts/tegra20-whistler.dts | 28 +++++++++++++++++
arch/arm/boot/dts/tegra20.dtsi | 49 +++++++++++++++++++++++-------
9 files changed, 143 insertions(+), 13 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
index e84f3f6..ec52937 100644
--- a/arch/arm/boot/dts/tegra20-harmony.dts
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
@@ -428,12 +428,17 @@
status = "okay";
};

+ usb-phy@c5000000 {
+ status = "okay";
+ };
+
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

usb-phy@c5004000 {
+ status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

@@ -441,6 +446,10 @@
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
sdhci@c8000200 {
status = "okay";
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
diff --git a/arch/arm/boot/dts/tegra20-iris-512.dts b/arch/arm/boot/dts/tegra20-iris-512.dts
index 52f1103..9f64f70 100644
--- a/arch/arm/boot/dts/tegra20-iris-512.dts
+++ b/arch/arm/boot/dts/tegra20-iris-512.dts
@@ -38,13 +38,20 @@

usb@c5000000 {
status = "okay";
- dr_mode = "otg";
+ };
+
+ usb-phy@c5000000 {
+ status = "okay";
};

usb@c5008000 {
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
serial@70006000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
index e9ac2a9..1c17ffa 100644
--- a/arch/arm/boot/dts/tegra20-paz00.dts
+++ b/arch/arm/boot/dts/tegra20-paz00.dts
@@ -427,12 +427,17 @@
status = "okay";
};

+ usb-phy@c5000000 {
+ status = "okay";
+ };
+
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

usb-phy@c5004000 {
+ status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

@@ -440,6 +445,10 @@
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
sdhci@c8000000 {
status = "okay";
cd-gpios = <&gpio 173 1>; /* gpio PV5 */
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 9dd4f8e..b832088 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -569,12 +569,19 @@
dr_mode = "otg";
};

+ usb-phy@c5000000 {
+ status = "okay";
+ vbus-supply = <&vbus_reg>;
+ dr_mode = "otg";
+ };
+
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

usb-phy@c5004000 {
+ status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

@@ -582,6 +589,10 @@
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
sdhci@c8000000 {
status = "okay";
power-gpios = <&gpio 86 0>; /* gpio PK6 */
@@ -807,6 +818,15 @@
gpio = <&pmic 1 0>;
enable-active-high;
};
+
+ vbus_reg: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "vdd_5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio 24 0>; /* PD0 */
+ };
};

sound {
diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi
index 50b3ec1..fc2f7d6 100644
--- a/arch/arm/boot/dts/tegra20-tamonten.dtsi
+++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi
@@ -470,6 +470,10 @@
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
sdhci@c8000600 {
cd-gpios = <&gpio 58 1>; /* gpio PH2 */
wp-gpios = <&gpio 59 0>; /* gpio PH3 */
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
index fd7afd6..d9b58cd 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -314,12 +314,18 @@
nvidia,vbus-gpio = <&gpio 170 0>; /* gpio PV2 */
};

+ usb-phy@c5000000 {
+ status = "okay";
+ vbus-supply = <&vbus_reg>;
+ };
+
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

usb-phy@c5004000 {
+ status = "okay";
nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

@@ -327,6 +333,10 @@
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
sdhci@c8000000 {
status = "okay";
bus-width = <4>;
@@ -390,6 +400,15 @@
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
+
+ vbus_reg: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "vdd_5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio 170 0>; /* PV2 */
+ };
};

sound {
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index a75a0e7..e00f89e 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -505,12 +505,17 @@
status = "okay";
};

+ usb-phy@c5000000 {
+ status = "okay";
+ };
+
usb@c5004000 {
status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

usb-phy@c5004000 {
+ status = "okay";
nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

@@ -518,6 +523,10 @@
status = "okay";
};

+ usb-phy@c5008000 {
+ status = "okay";
+ };
+
sdhci@c8000000 {
status = "okay";
power-gpios = <&gpio 86 0>; /* gpio PK6 */
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
index d2567f8..e405c2f 100644
--- a/arch/arm/boot/dts/tegra20-whistler.dts
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -511,11 +511,21 @@
nvidia,vbus-gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
};

+ usb-phy@c5000000 {
+ status = "okay";
+ vbus-supply = <&vbus_reg1>;
+ };
+
usb@c5008000 {
status = "okay";
nvidia,vbus-gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
};

+ usb-phy@c5008000 {
+ status = "okay";
+ vbus-supply = <&vbus_reg2>;
+ };
+
sdhci@c8000400 {
status = "okay";
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
@@ -568,6 +578,24 @@
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
+
+ vbus_reg1: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "vdd_5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
+ };
+
+ vbus_reg2: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "vdd_5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
+ };
};

sound {
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 56a9110..96d6d8a 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -455,13 +455,24 @@
status = "disabled";
};

- phy1: usb-phy@c5000400 {
+ phy1: usb-phy@c5000000 {
compatible = "nvidia,tegra20-usb-phy";
- reg = <0xc5000400 0x3c00>;
+ reg = <0xc5000000 0x4000 0xc5000000 0x4000>;
phy_type = "utmi";
+ clocks = <&tegra_car 22>,
+ <&tegra_car 127>,
+ <&tegra_car 106>,
+ <&tegra_car 22>;
+ clock-names = "reg", "pll_u", "timer", "utmi-pads";
nvidia,has-legacy-mode;
- clocks = <&tegra_car 22>, <&tegra_car 127>;
- clock-names = "phy", "pll_u";
+ hssync_start_delay = <9>;
+ idle_wait_delay = <17>;
+ elastic_limit = <16>;
+ term_range_adj = <6>;
+ xcvr_setup = <9>;
+ xcvr_lsfslew = <1>;
+ xcvr_lsrslew = <1>;
+ status = "disabled";
};

usb@c5004000 {
@@ -474,12 +485,15 @@
status = "disabled";
};

- phy2: usb-phy@c5004400 {
+ phy2: usb-phy@c5004000 {
compatible = "nvidia,tegra20-usb-phy";
- reg = <0xc5004400 0x3c00>;
+ reg = <0xc5004000 0x4000>;
phy_type = "ulpi";
- clocks = <&tegra_car 93>, <&tegra_car 127>;
- clock-names = "phy", "pll_u";
+ clocks = <&tegra_car 58>,
+ <&tegra_car 127>,
+ <&tegra_car 93>;
+ clock-names = "reg", "pll_u", "ulpi-link";
+ status = "disabled";
};

usb@c5008000 {
@@ -492,12 +506,23 @@
status = "disabled";
};

- phy3: usb-phy@c5008400 {
+ phy3: usb-phy@c5008000 {
compatible = "nvidia,tegra20-usb-phy";
- reg = <0xc5008400 0x3c00>;
+ reg = <0xc5008000 0x4000 0xc5000000 0x4000>;
phy_type = "utmi";
- clocks = <&tegra_car 22>, <&tegra_car 127>;
- clock-names = "phy", "pll_u";
+ clocks = <&tegra_car 59>,
+ <&tegra_car 127>,
+ <&tegra_car 106>,
+ <&tegra_car 22>;
+ clock-names = "reg", "pll_u", "timer", "utmi-pads";
+ hssync_start_delay = <9>;
+ idle_wait_delay = <17>;
+ elastic_limit = <16>;
+ term_range_adj = <6>;
+ xcvr_setup = <9>;
+ xcvr_lsfslew = <2>;
+ xcvr_lsrslew = <2>;
+ status = "disabled";
};

sdhci@c8000000 {
--
1.7.0.4

2013-05-16 14:22:25

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 5/8] usb: phy: tegra: Get PHY mode using DT

Added a new PHY mode to support OTG.
Obtained Tegra USB PHY mode using DT property.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v3 & v2:
No change

delta from v1:
replaced gadget with peripheral.



drivers/usb/host/ehci-tegra.c | 1 -
drivers/usb/phy/phy-tegra-usb.c | 13 +++++++++++--
include/linux/usb/tegra_usb_phy.h | 3 ++-
3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index e3eddc3..568a6fa 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -736,7 +736,6 @@ static int tegra_ehci_probe(struct platform_device *pdev)

tegra->phy = tegra_usb_phy_open(&pdev->dev, instance, hcd->regs,
pdata->phy_config,
- TEGRA_USB_PHY_MODE_HOST,
tegra_ehci_set_pts,
tegra_ehci_set_phcd);
if (IS_ERR(tegra->phy)) {
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 8bcc12f..0ff1f3e 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -687,7 +687,7 @@ static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
}

struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
- void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode,
+ void __iomem *regs, void *config,
void (*set_pts)(struct usb_phy *x, u8 pts_val),
void (*set_phcd)(struct usb_phy *x, bool enable))

@@ -705,7 +705,6 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
phy->instance = instance;
phy->regs = regs;
phy->config = config;
- phy->mode = phy_mode;
phy->dev = dev;
phy->is_legacy_phy =
of_property_read_bool(np, "nvidia,has-legacy-mode");
@@ -717,6 +716,16 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
else
phy->is_ulpi_phy = true;

+ err = of_property_match_string(np, "dr_mode", "otg");
+ if (err < 0) {
+ err = of_property_match_string(np, "dr_mode", "peripheral");
+ if (err < 0)
+ phy->mode = TEGRA_USB_PHY_MODE_HOST;
+ else
+ phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
+ } else
+ phy->mode = TEGRA_USB_PHY_MODE_OTG;
+
if (!phy->config) {
if (phy->is_ulpi_phy) {
pr_err("%s: ulpi phy configuration missing", __func__);
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index 1b7519a..ff2d959 100644
--- a/include/linux/usb/tegra_usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -42,6 +42,7 @@ enum tegra_usb_phy_port_speed {
enum tegra_usb_phy_mode {
TEGRA_USB_PHY_MODE_DEVICE,
TEGRA_USB_PHY_MODE_HOST,
+ TEGRA_USB_PHY_MODE_OTG,
};

struct tegra_xtal_freq;
@@ -66,7 +67,7 @@ struct tegra_usb_phy {
};

struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
- void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode,
+ void __iomem *regs, void *config,
void (*set_pts)(struct usb_phy *x, u8 pts_val),
void (*set_phcd)(struct usb_phy *x, bool enable));

--
1.7.0.4

2013-05-16 14:22:34

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 7/8] usb: phy: tegra: Add error handling & clean up.

Check return values from all GPIO APIs and handle errors accordingly.

Remove the call to clk_disable_unprepare(); this function does not
prepare or enable the clock, so the error path should not disable or
unprepare it.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v3:
Modified comment section to indicate 'otg_ulpi_create returned NULL'.

delta from v2:
Fixed checkpatch warnings.

delta from v1:
no changes.

drivers/usb/phy/phy-tegra-usb.c | 50 ++++++++++++++++++++++++++++++--------
1 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index b8c688a..f423ae8 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -542,9 +542,17 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
unsigned long val;
void __iomem *base = phy->regs;

- gpio_direction_output(phy->reset_gpio, 0);
+ ret = gpio_direction_output(phy->reset_gpio, 0);
+ if (ret < 0) {
+ dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio);
+ return ret;
+ }
msleep(5);
- gpio_direction_output(phy->reset_gpio, 1);
+ ret = gpio_direction_output(phy->reset_gpio, 1);
+ if (ret < 0) {
+ dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio);
+ return ret;
+ }

clk_prepare_enable(phy->clk);
msleep(1);
@@ -624,24 +632,44 @@ static int tegra_phy_init(struct usb_phy *x)
of_get_named_gpio(phy->dev->of_node,
"nvidia,phy-reset-gpio", 0);
if (!gpio_is_valid(phy->reset_gpio)) {
- pr_err("%s: invalid reset gpio: %d\n", __func__,
+ dev_err(phy->dev, "invalid gpio: %d\n",
+ phy->reset_gpio);
+ err = phy->reset_gpio;
+ goto cleanup_clk_get;
+ }
+
+ err = gpio_request(phy->reset_gpio, "ulpi_phy_reset_b");
+ if (err < 0) {
+ dev_err(phy->dev, "request failed for gpio: %d\n",
phy->reset_gpio);
- err = -EINVAL;
- goto err1;
+ goto cleanup_clk_get;
+ }
+
+ err = gpio_direction_output(phy->reset_gpio, 0);
+ if (err < 0) {
+ dev_err(phy->dev, "gpio %d direction not set to output\n",
+ phy->reset_gpio);
+ goto cleanup_gpio_req;
}
- gpio_request(phy->reset_gpio, "ulpi_phy_reset_b");
- gpio_direction_output(phy->reset_gpio, 0);
+
phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ if (!phy->ulpi) {
+ dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
+ err = -ENOMEM;
+ goto cleanup_gpio_req;
+ }
+
phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
} else {
err = utmip_pad_open(phy);
if (err < 0)
- goto err1;
+ return err;
}
return 0;
-err1:
- clk_disable_unprepare(phy->pll_u);
- clk_put(phy->pll_u);
+cleanup_gpio_req:
+ gpio_free(phy->reset_gpio);
+cleanup_clk_get:
+ clk_put(phy->clk);
return err;
}

--
1.7.0.4

2013-05-16 14:22:39

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 8/8] usb: phy: registering Tegra USB PHY as platform driver

Registered Tegra USB PHY as a separate platform driver.

To synchronize host controller and PHY initialization, used deferred
probe mechanism. As PHY should be initialized before EHCI starts running,
deferred probe of Tegra EHCI driver till PHY probe gets completed.

Got rid of instance number based handling in host driver.

Made use of DT params to get the PHY Pad registers.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v3:
Removed functions pointers to access PORTSC registers from PHY & accessing
them from PHY using exported functions.

delta from v2:
Rebased to TOT and applied same changes as on v2.

delta from v1:
1. Removed extra memory allocation for u_phy->otg
2. Moved ulpi_init code into separate function.
3. Initializing all clk and GPIOs in probe.
4. Used devm_ APIs wherever possible.

drivers/usb/host/ehci-tegra.c | 104 +++++-------
drivers/usb/phy/phy-tegra-usb.c | 325 ++++++++++++++++++++-----------------
include/linux/usb/tegra_usb_phy.h | 11 +-
3 files changed, 230 insertions(+), 210 deletions(-)

diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 568a6fa..c8ee919 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -611,7 +611,7 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = {
/* Bits of PORTSC1, which will get cleared by writing 1 into them */
#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)

-static void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
+void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
{
unsigned long val;
struct usb_hcd *hcd = bus_to_hcd(x->otg->host);
@@ -622,8 +622,9 @@ static void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3);
writel(val, base + TEGRA_USB_PORTSC1);
}
+EXPORT_SYMBOL_GPL(tegra_ehci_set_pts);

-static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
+void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
{
unsigned long val;
struct usb_hcd *hcd = bus_to_hcd(x->otg->host);
@@ -636,6 +637,7 @@ static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
val &= ~TEGRA_USB_PORTSC1_PHCD;
writel(val, base + TEGRA_USB_PORTSC1);
}
+EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd);

static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32);

@@ -647,7 +649,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
struct tegra_ehci_platform_data *pdata;
int err = 0;
int irq;
- int instance = pdev->id;
+ struct device_node *np_phy;
struct usb_phy *u_phy;

pdata = pdev->dev.platform_data;
@@ -670,38 +672,49 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!tegra)
return -ENOMEM;

- hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
- dev_name(&pdev->dev));
- if (!hcd) {
- dev_err(&pdev->dev, "Unable to create HCD\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(pdev, tegra);
-
tegra->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tegra->clk)) {
dev_err(&pdev->dev, "Can't get ehci clock\n");
- err = PTR_ERR(tegra->clk);
- goto fail_clk;
+ return PTR_ERR(tegra->clk);
}

err = clk_prepare_enable(tegra->clk);
if (err)
- goto fail_clk;
+ return err;

tegra_periph_reset_assert(tegra->clk);
udelay(1);
tegra_periph_reset_deassert(tegra->clk);

+ np_phy = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
+ if (!np_phy) {
+ err = -ENODEV;
+ goto cleanup_clk;
+ }
+
+ u_phy = tegra_usb_get_phy(np_phy);
+ if (IS_ERR(u_phy)) {
+ err = PTR_ERR(u_phy);
+ goto cleanup_clk;
+ }
+
tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node,
"nvidia,needs-double-reset");

+ hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd) {
+ dev_err(&pdev->dev, "Unable to create HCD\n");
+ err = -ENOMEM;
+ goto cleanup_clk;
+ }
+ hcd->phy = u_phy;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Failed to get I/O memory\n");
err = -ENXIO;
- goto fail_io;
+ goto cleanup_hcd_create;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
@@ -709,57 +722,28 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!hcd->regs) {
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
err = -ENOMEM;
- goto fail_io;
- }
-
- /* This is pretty ugly and needs to be fixed when we do only
- * device-tree probing. Old code relies on the platform_device
- * numbering that we lack for device-tree-instantiated devices.
- */
- if (instance < 0) {
- switch (res->start) {
- case TEGRA_USB_BASE:
- instance = 0;
- break;
- case TEGRA_USB2_BASE:
- instance = 1;
- break;
- case TEGRA_USB3_BASE:
- instance = 2;
- break;
- default:
- err = -ENODEV;
- dev_err(&pdev->dev, "unknown usb instance\n");
- goto fail_io;
- }
+ goto cleanup_hcd_create;
}

- tegra->phy = tegra_usb_phy_open(&pdev->dev, instance, hcd->regs,
- pdata->phy_config,
- tegra_ehci_set_pts,
- tegra_ehci_set_phcd);
- if (IS_ERR(tegra->phy)) {
- dev_err(&pdev->dev, "Failed to open USB phy\n");
- err = -ENXIO;
- goto fail_io;
+ err = usb_phy_init(hcd->phy);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to initialize phy\n");
+ goto cleanup_hcd_create;
}

- hcd->phy = u_phy = &tegra->phy->u_phy;
- usb_phy_init(hcd->phy);
-
u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
GFP_KERNEL);
if (!u_phy->otg) {
dev_err(&pdev->dev, "Failed to alloc memory for otg\n");
err = -ENOMEM;
- goto fail_io;
+ goto cleanup_phy;
}
u_phy->otg->host = hcd_to_bus(hcd);

err = usb_phy_set_suspend(hcd->phy, 0);
if (err) {
dev_err(&pdev->dev, "Failed to power on the phy\n");
- goto fail_phy;
+ goto cleanup_phy;
}

tegra->host_resumed = 1;
@@ -769,7 +753,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
err = -ENODEV;
- goto fail_phy;
+ goto cleanup_phy;
}

if (pdata->operating_mode == TEGRA_USB_OTG) {
@@ -781,10 +765,12 @@ static int tegra_ehci_probe(struct platform_device *pdev)
tegra->transceiver = ERR_PTR(-ENODEV);
}

+ platform_set_drvdata(pdev, tegra);
+
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
- goto fail;
+ goto cleanup_phy;
}

pm_runtime_set_active(&pdev->dev);
@@ -797,15 +783,15 @@ static int tegra_ehci_probe(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
return err;

-fail:
+cleanup_phy:
if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL);
-fail_phy:
+
usb_phy_shutdown(hcd->phy);
-fail_io:
- clk_disable_unprepare(tegra->clk);
-fail_clk:
+cleanup_hcd_create:
usb_put_hcd(hcd);
+cleanup_clk:
+ clk_disable_unprepare(tegra->clk);
return err;
}

diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index f423ae8..4d81b19 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -1,9 +1,11 @@
/*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2013 NVIDIA Corporation
*
* Author:
* Erik Gilling <[email protected]>
* Benoit Goby <[email protected]>
+ * Venu Byravarasu <[email protected]>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -30,9 +32,7 @@
#include <linux/usb/ulpi.h>
#include <asm/mach-types.h>
#include <linux/usb/tegra_usb_phy.h>
-
-#define TEGRA_USB_BASE 0xC5000000
-#define TEGRA_USB_SIZE SZ_16K
+#include <linux/module.h>

#define ULPI_VIEWPORT 0x170

@@ -198,32 +198,15 @@ static struct tegra_utmip_config utmip_default[] = {

static int utmip_pad_open(struct tegra_usb_phy *phy)
{
- phy->pad_clk = clk_get_sys("utmip-pad", NULL);
+ phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads");
if (IS_ERR(phy->pad_clk)) {
pr_err("%s: can't get utmip pad clock\n", __func__);
return PTR_ERR(phy->pad_clk);
}

- if (phy->is_legacy_phy) {
- phy->pad_regs = phy->regs;
- } else {
- phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
- if (!phy->pad_regs) {
- pr_err("%s: can't remap usb registers\n", __func__);
- clk_put(phy->pad_clk);
- return -ENOMEM;
- }
- }
return 0;
}

-static void utmip_pad_close(struct tegra_usb_phy *phy)
-{
- if (!phy->is_legacy_phy)
- iounmap(phy->pad_regs);
- clk_put(phy->pad_clk);
-}
-
static void utmip_pad_power_on(struct tegra_usb_phy *phy)
{
unsigned long val, flags;
@@ -299,7 +282,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
val &= ~USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
} else
- phy->set_phcd(&phy->u_phy, true);
+ tegra_ehci_set_phcd(&phy->u_phy, true);

if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
@@ -321,7 +304,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
val &= ~USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
} else
- phy->set_phcd(&phy->u_phy, false);
+ tegra_ehci_set_phcd(&phy->u_phy, false);

if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
USB_PHY_CLK_VALID))
@@ -444,7 +427,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
utmi_phy_clk_enable(phy);

if (!phy->is_legacy_phy)
- phy->set_pts(&phy->u_phy, 0);
+ tegra_ehci_set_pts(&phy->u_phy, 0);

return 0;
}
@@ -614,76 +597,11 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
return gpio_direction_output(phy->reset_gpio, 0);
}

-static int tegra_phy_init(struct usb_phy *x)
-{
- struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
- struct tegra_ulpi_config *ulpi_config;
- int err;
-
- if (phy->is_ulpi_phy) {
- ulpi_config = phy->config;
- phy->clk = clk_get_sys(NULL, ulpi_config->clk);
- if (IS_ERR(phy->clk)) {
- pr_err("%s: can't get ulpi clock\n", __func__);
- return PTR_ERR(phy->clk);
- }
-
- phy->reset_gpio =
- of_get_named_gpio(phy->dev->of_node,
- "nvidia,phy-reset-gpio", 0);
- if (!gpio_is_valid(phy->reset_gpio)) {
- dev_err(phy->dev, "invalid gpio: %d\n",
- phy->reset_gpio);
- err = phy->reset_gpio;
- goto cleanup_clk_get;
- }
-
- err = gpio_request(phy->reset_gpio, "ulpi_phy_reset_b");
- if (err < 0) {
- dev_err(phy->dev, "request failed for gpio: %d\n",
- phy->reset_gpio);
- goto cleanup_clk_get;
- }
-
- err = gpio_direction_output(phy->reset_gpio, 0);
- if (err < 0) {
- dev_err(phy->dev, "gpio %d direction not set to output\n",
- phy->reset_gpio);
- goto cleanup_gpio_req;
- }
-
- phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
- if (!phy->ulpi) {
- dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
- err = -ENOMEM;
- goto cleanup_gpio_req;
- }
-
- phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
- } else {
- err = utmip_pad_open(phy);
- if (err < 0)
- return err;
- }
- return 0;
-cleanup_gpio_req:
- gpio_free(phy->reset_gpio);
-cleanup_clk_get:
- clk_put(phy->clk);
- return err;
-}
-
static void tegra_usb_phy_close(struct usb_phy *x)
{
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);

- if (phy->is_ulpi_phy)
- clk_put(phy->clk);
- else
- utmip_pad_close(phy);
clk_disable_unprepare(phy->pll_u);
- clk_put(phy->pll_u);
- kfree(phy);
}

static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
@@ -711,63 +629,63 @@ static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
return tegra_usb_phy_power_on(phy);
}

-struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
- void __iomem *regs, void *config,
- void (*set_pts)(struct usb_phy *x, u8 pts_val),
- void (*set_phcd)(struct usb_phy *x, bool enable))
-
+static int ulpi_open(struct tegra_usb_phy *phy)
{
- struct tegra_usb_phy *phy;
- unsigned long parent_rate;
- int i;
int err;
- struct device_node *np = dev->of_node;

- phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
- if (!phy)
- return ERR_PTR(-ENOMEM);
+ phy->clk = devm_clk_get(phy->dev, "ulpi-link");
+ if (IS_ERR(phy->clk)) {
+ pr_err("%s: can't get ulpi clock\n", __func__);
+ return PTR_ERR(phy->clk);
+ }

- phy->instance = instance;
- phy->regs = regs;
- phy->config = config;
- phy->dev = dev;
- phy->is_legacy_phy =
- of_property_read_bool(np, "nvidia,has-legacy-mode");
- phy->set_pts = set_pts;
- phy->set_phcd = set_phcd;
- err = of_property_match_string(np, "phy_type", "ulpi");
- if (err < 0)
- phy->is_ulpi_phy = false;
- else
- phy->is_ulpi_phy = true;
+ err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b");
+ if (err < 0) {
+ dev_err(phy->dev, "request failed for gpio: %d\n",
+ phy->reset_gpio);
+ return err;
+ }

- err = of_property_match_string(np, "dr_mode", "otg");
+ err = gpio_direction_output(phy->reset_gpio, 0);
if (err < 0) {
- err = of_property_match_string(np, "dr_mode", "peripheral");
- if (err < 0)
- phy->mode = TEGRA_USB_PHY_MODE_HOST;
+ dev_err(phy->dev, "gpio %d direction not set to output\n",
+ phy->reset_gpio);
+ return err;
+ }
+
+ phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ if (!phy->ulpi) {
+ dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
+ err = -ENOMEM;
+ return err;
+ }
+
+ phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
+ return 0;
+}
+
+static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+ int err;
+
+ if (!phy->is_ulpi_phy) {
+ if (phy->is_legacy_phy)
+ phy->config = &utmip_default[0];
else
- phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
- } else
- phy->mode = TEGRA_USB_PHY_MODE_OTG;
-
- if (!phy->config) {
- if (phy->is_ulpi_phy) {
- pr_err("%s: ulpi phy configuration missing", __func__);
- err = -EINVAL;
- goto err0;
- } else {
- phy->config = &utmip_default[instance];
- }
+ phy->config = &utmip_default[2];
}

- phy->pll_u = clk_get_sys(NULL, "pll_u");
+ phy->pll_u = devm_clk_get(phy->dev, "pll_u");
if (IS_ERR(phy->pll_u)) {
pr_err("Can't get pll_u clock\n");
- err = PTR_ERR(phy->pll_u);
- goto err0;
+ return PTR_ERR(phy->pll_u);
}
- clk_prepare_enable(phy->pll_u);
+
+ err = clk_prepare_enable(phy->pll_u);
+ if (err)
+ return err;

parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
@@ -779,23 +697,22 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
if (!phy->freq) {
pr_err("invalid pll_u parent rate %ld\n", parent_rate);
err = -EINVAL;
- goto err1;
+ goto fail;
}

- phy->u_phy.init = tegra_phy_init;
- phy->u_phy.shutdown = tegra_usb_phy_close;
- phy->u_phy.set_suspend = tegra_usb_phy_suspend;
+ if (phy->is_ulpi_phy)
+ err = ulpi_open(phy);
+ else
+ err = utmip_pad_open(phy);
+ if (err < 0)
+ goto fail;

- return phy;
+ return 0;

-err1:
+fail:
clk_disable_unprepare(phy->pll_u);
- clk_put(phy->pll_u);
-err0:
- kfree(phy);
- return ERR_PTR(err);
+ return err;
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_open);

void tegra_usb_phy_preresume(struct usb_phy *x)
{
@@ -834,3 +751,121 @@ void tegra_ehci_phy_restore_end(struct usb_phy *x)
}
EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);

+static int tegra_usb_phy_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct tegra_usb_phy *tegra_phy = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ int err;
+
+ tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
+ if (!tegra_phy) {
+ dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get I/O memory\n");
+ return -ENXIO;
+ }
+
+ tegra_phy->regs = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!tegra_phy->regs) {
+ dev_err(&pdev->dev, "Failed to remap I/O memory\n");
+ return -ENOMEM;
+ }
+
+ tegra_phy->is_legacy_phy =
+ of_property_read_bool(np, "nvidia,has-legacy-mode");
+
+ err = of_property_match_string(np, "phy_type", "ulpi");
+ if (err < 0) {
+ tegra_phy->is_ulpi_phy = false;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
+ return -ENXIO;
+ }
+
+ tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!tegra_phy->regs) {
+ dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
+ return -ENOMEM;
+ }
+ } else {
+ tegra_phy->is_ulpi_phy = true;
+
+ tegra_phy->reset_gpio =
+ of_get_named_gpio(np, "nvidia,phy-reset-gpio", 0);
+ if (!gpio_is_valid(tegra_phy->reset_gpio)) {
+ dev_err(&pdev->dev, "invalid gpio: %d\n",
+ tegra_phy->reset_gpio);
+ return tegra_phy->reset_gpio;
+ }
+ }
+
+ err = of_property_match_string(np, "dr_mode", "otg");
+ if (err < 0) {
+ err = of_property_match_string(np, "dr_mode", "peripheral");
+ if (err < 0)
+ tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST;
+ else
+ tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
+ } else
+ tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG;
+
+ tegra_phy->dev = &pdev->dev;
+ err = tegra_usb_phy_init(tegra_phy);
+ if (err < 0)
+ return err;
+
+ tegra_phy->u_phy.shutdown = tegra_usb_phy_close;
+ tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
+
+ dev_set_drvdata(&pdev->dev, tegra_phy);
+ return 0;
+}
+
+static struct of_device_id tegra_usb_phy_id_table[] = {
+ { .compatible = "nvidia,tegra20-usb-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+
+static struct platform_driver tegra_usb_phy_driver = {
+ .probe = tegra_usb_phy_probe,
+ .driver = {
+ .name = "tegra-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tegra_usb_phy_id_table),
+ },
+};
+module_platform_driver(tegra_usb_phy_driver);
+
+static int tegra_usb_phy_match(struct device *dev, void *data)
+{
+ struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev);
+ struct device_node *dn = data;
+
+ return (tegra_phy->dev->of_node == dn) ? 1 : 0;
+}
+
+struct usb_phy *tegra_usb_get_phy(struct device_node *dn)
+{
+ struct device *dev;
+ struct tegra_usb_phy *tegra_phy;
+
+ dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn,
+ tegra_usb_phy_match);
+ if (!dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ tegra_phy = dev_get_drvdata(dev);
+
+ return &tegra_phy->u_phy;
+}
+EXPORT_SYMBOL_GPL(tegra_usb_get_phy);
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index 97d123c..0cd15d2 100644
--- a/include/linux/usb/tegra_usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -63,14 +63,9 @@ struct tegra_usb_phy {
bool is_legacy_phy;
bool is_ulpi_phy;
int reset_gpio;
- void (*set_pts)(struct usb_phy *x, u8 pts_val);
- void (*set_phcd)(struct usb_phy *x, bool enable);
};

-struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
- void __iomem *regs, void *config,
- void (*set_pts)(struct usb_phy *x, u8 pts_val),
- void (*set_phcd)(struct usb_phy *x, bool enable));
+struct usb_phy *tegra_usb_get_phy(struct device_node *dn);

void tegra_usb_phy_preresume(struct usb_phy *phy);

@@ -81,4 +76,8 @@ void tegra_ehci_phy_restore_start(struct usb_phy *phy,

void tegra_ehci_phy_restore_end(struct usb_phy *phy);

+void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val);
+
+void tegra_ehci_set_phcd(struct usb_phy *x, bool enable);
+
#endif /* __TEGRA_USB_PHY_H */
--
1.7.0.4

2013-05-16 14:23:10

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 6/8] usb: phy: tegra: get ULPI reset GPIO info using DT.

As GPIO information is avail through DT, used it to get Tegra ULPI
reset GPIO number. Added a new member to tegra_usb_phy structure to
store this number.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v1, v2 & v3: no change.

drivers/usb/phy/phy-tegra-usb.c | 25 +++++++++++--------------
include/linux/usb/tegra_usb_phy.h | 1 +
2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 0ff1f3e..b8c688a 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -541,11 +541,10 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
int ret;
unsigned long val;
void __iomem *base = phy->regs;
- struct tegra_ulpi_config *config = phy->config;

- gpio_direction_output(config->reset_gpio, 0);
+ gpio_direction_output(phy->reset_gpio, 0);
msleep(5);
- gpio_direction_output(config->reset_gpio, 1);
+ gpio_direction_output(phy->reset_gpio, 1);

clk_prepare_enable(phy->clk);
msleep(1);
@@ -603,10 +602,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)

static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
{
- struct tegra_ulpi_config *config = phy->config;
-
clk_disable(phy->clk);
- return gpio_direction_output(config->reset_gpio, 0);
+ return gpio_direction_output(phy->reset_gpio, 0);
}

static int tegra_phy_init(struct usb_phy *x)
@@ -622,18 +619,18 @@ static int tegra_phy_init(struct usb_phy *x)
pr_err("%s: can't get ulpi clock\n", __func__);
return PTR_ERR(phy->clk);
}
- if (!gpio_is_valid(ulpi_config->reset_gpio))
- ulpi_config->reset_gpio =
- of_get_named_gpio(phy->dev->of_node,
- "nvidia,phy-reset-gpio", 0);
- if (!gpio_is_valid(ulpi_config->reset_gpio)) {
+
+ phy->reset_gpio =
+ of_get_named_gpio(phy->dev->of_node,
+ "nvidia,phy-reset-gpio", 0);
+ if (!gpio_is_valid(phy->reset_gpio)) {
pr_err("%s: invalid reset gpio: %d\n", __func__,
- ulpi_config->reset_gpio);
+ phy->reset_gpio);
err = -EINVAL;
goto err1;
}
- gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
- gpio_direction_output(ulpi_config->reset_gpio, 0);
+ gpio_request(phy->reset_gpio, "ulpi_phy_reset_b");
+ gpio_direction_output(phy->reset_gpio, 0);
phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
} else {
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index ff2d959..97d123c 100644
--- a/include/linux/usb/tegra_usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -62,6 +62,7 @@ struct tegra_usb_phy {
struct device *dev;
bool is_legacy_phy;
bool is_ulpi_phy;
+ int reset_gpio;
void (*set_pts)(struct usb_phy *x, u8 pts_val);
void (*set_phcd)(struct usb_phy *x, bool enable);
};
--
1.7.0.4

2013-05-16 14:22:17

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 2/8] arm: dt: Tegra20: Modify ULPI reset GPIO properties

1. All Tegra20 ULPI reset GPIO DT properties are modified to indicate active
low nature of the GPIO.
2. Placed USB PHY DT node immediately below the EHCI controller DT nodes
and corrected reg value in the name of USB PHY DT node.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v3:
No code changes. Commit message only updated.

delta from v2:
Created this patch as per comments received at:
http://marc.info/?l=linux-usb&m=136501761810344&w=2

arch/arm/boot/dts/tegra20-colibri-512.dtsi | 6 +++++-
arch/arm/boot/dts/tegra20-harmony.dts | 10 +++++-----
arch/arm/boot/dts/tegra20-paz00.dts | 10 +++++-----
arch/arm/boot/dts/tegra20-seaboard.dts | 10 +++++-----
arch/arm/boot/dts/tegra20-trimslice.dts | 10 +++++-----
arch/arm/boot/dts/tegra20-ventana.dts | 10 +++++-----
6 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20-colibri-512.dtsi b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
index a573b94..c12af78 100644
--- a/arch/arm/boot/dts/tegra20-colibri-512.dtsi
+++ b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
@@ -449,7 +449,11 @@

usb@c5004000 {
status = "okay";
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
+ };
+
+ usb-phy@c5004000 {
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

sdhci@c8000600 {
diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
index e7d5de4..e84f3f6 100644
--- a/arch/arm/boot/dts/tegra20-harmony.dts
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
@@ -430,15 +430,15 @@

usb@c5004000 {
status = "okay";
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

- usb@c5008000 {
- status = "okay";
+ usb-phy@c5004000 {
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

- usb-phy@c5004400 {
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ usb@c5008000 {
+ status = "okay";
};

sdhci@c8000200 {
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
index e3e0c99..e9ac2a9 100644
--- a/arch/arm/boot/dts/tegra20-paz00.dts
+++ b/arch/arm/boot/dts/tegra20-paz00.dts
@@ -429,15 +429,15 @@

usb@c5004000 {
status = "okay";
- nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

- usb@c5008000 {
- status = "okay";
+ usb-phy@c5004000 {
+ nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

- usb-phy@c5004400 {
- nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ usb@c5008000 {
+ status = "okay";
};

sdhci@c8000000 {
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index cee4c34..9dd4f8e 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -571,15 +571,15 @@

usb@c5004000 {
status = "okay";
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

- usb@c5008000 {
- status = "okay";
+ usb-phy@c5004000 {
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

- usb-phy@c5004400 {
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ usb@c5008000 {
+ status = "okay";
};

sdhci@c8000000 {
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
index 9cc78a1..fd7afd6 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -316,15 +316,15 @@

usb@c5004000 {
status = "okay";
- nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

- usb@c5008000 {
- status = "okay";
+ usb-phy@c5004000 {
+ nvidia,phy-reset-gpio = <&gpio 168 1>; /* gpio PV0, active low */
};

- usb-phy@c5004400 {
- nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ usb@c5008000 {
+ status = "okay";
};

sdhci@c8000000 {
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index dd38f1f..a75a0e7 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -507,15 +507,15 @@

usb@c5004000 {
status = "okay";
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

- usb@c5008000 {
- status = "okay";
+ usb-phy@c5004000 {
+ nvidia,phy-reset-gpio = <&gpio 169 1>; /* gpio PV1, active low */
};

- usb-phy@c5004400 {
- nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ usb@c5008000 {
+ status = "okay";
};

sdhci@c8000000 {
--
1.7.0.4

2013-05-16 14:23:54

by Venu Byravarasu

[permalink] [raw]
Subject: [PATCH v4 4/8] usb: phy: tegra: Return correct error value provided by clk_get_sys

In case if clk_get_sys fails, return correct error value provided by
the API.

Signed-off-by: Venu Byravarasu <[email protected]>
---
delta from v1, v2 & v3: no change.

drivers/usb/phy/phy-tegra-usb.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 17d8112..8bcc12f 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -620,8 +620,7 @@ static int tegra_phy_init(struct usb_phy *x)
phy->clk = clk_get_sys(NULL, ulpi_config->clk);
if (IS_ERR(phy->clk)) {
pr_err("%s: can't get ulpi clock\n", __func__);
- err = -ENXIO;
- goto err1;
+ return PTR_ERR(phy->clk);
}
if (!gpio_is_valid(ulpi_config->reset_gpio))
ulpi_config->reset_gpio =
--
1.7.0.4

2013-05-16 21:08:35

by Stephen Warren

[permalink] [raw]
Subject: Re: [PATCH v4 7/8] usb: phy: tegra: Add error handling & clean up.

On 05/16/2013 08:13 AM, Venu Byravarasu wrote:
> Check return values from all GPIO APIs and handle errors accordingly.
>
> Remove the call to clk_disable_unprepare(); this function does not
> prepare or enable the clock, so the error path should not disable or
> unprepare it.
>
> Signed-off-by: Venu Byravarasu <[email protected]>
> ---
> delta from v3:
> Modified comment section to indicate 'otg_ulpi_create returned NULL'.

I'm being really anal here, but note this wasn't a change to a comment,
but to the error message printed by the code.

2013-05-16 23:02:18

by Stephen Warren

[permalink] [raw]
Subject: Re: [PATCH v4 3/8] ARM: tegra: update device trees for USB binding rework

On 05/16/2013 08:12 AM, Venu Byravarasu wrote:
> This patch updates all Tegra board files so that they contain all the
> properties required by the updated USB DT binding. Note that this patch
> only adds the new properties and does not yet remove the old properties,
> in order to maintain bisectability. The old properties will be removed
> once the driver has been updated to assume the new bindings.

This series looks almost OK now. The one remaining issue is that in this
patch, the regulator-name properties don't match the schematics, and in
the Whistler patch below, both regulators you added have the same
regulator-name, which causes problems.

To fix this, when I apply this patch, I'm going to fold in the patch
I'll paste below.

Right now, I can't get Whistler to see the SD card. This is true even
without your patches. Once I've resolved that and tested Whistler,
assuming no more problems, I'll apply patches 1-3 to the Tegra tree, and
set up a branch that can be pulled into the USB tree so the rest of the
series can be applied there.

diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts
b/arch/arm/boot/dts/tegra20-seaboard.dts
index b832088..009dafe 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -822,7 +822,7 @@
vbus_reg: regulator@3 {
compatible = "regulator-fixed";
reg = <3>;
- regulator-name = "vdd_5v0";
+ regulator-name = "vdd_vbus_wup1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio 24 0>; /* PD0 */
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts
b/arch/arm/boot/dts/tegra20-trimslice.dts
index d9b58cd..0e65c00e 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -404,7 +404,7 @@
vbus_reg: regulator@2 {
compatible = "regulator-fixed";
reg = <2>;
- regulator-name = "vdd_5v0";
+ regulator-name = "usb1_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio 170 0>; /* PV2 */
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts
b/arch/arm/boot/dts/tegra20-whistler.dts
index e405c2f..3c24c9b 100644
--- a/arch/arm/boot/dts/tegra20-whistler.dts
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -513,7 +513,7 @@

usb-phy@c5000000 {
status = "okay";
- vbus-supply = <&vbus_reg1>;
+ vbus-supply = <&vbus1_reg>;
};

usb@c5008000 {
@@ -523,7 +523,7 @@

usb-phy@c5008000 {
status = "okay";
- vbus-supply = <&vbus_reg2>;
+ vbus-supply = <&vbus3_reg>;
};

sdhci@c8000400 {
@@ -579,19 +579,19 @@
regulator-always-on;
};

- vbus_reg1: regulator@2 {
+ vbus1_reg: regulator@2 {
compatible = "regulator-fixed";
reg = <2>;
- regulator-name = "vdd_5v0";
+ regulator-name = "vbus1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
};

- vbus_reg2: regulator@3 {
+ vbus3_reg: regulator@3 {
compatible = "regulator-fixed";
reg = <3>;
- regulator-name = "vdd_5v0";
+ regulator-name = "vbus3";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
--
1.7.10.4

2013-05-17 22:06:33

by Stephen Warren

[permalink] [raw]
Subject: Re: [PATCH v4 3/8] ARM: tegra: update device trees for USB binding rework

On 05/16/2013 05:02 PM, Stephen Warren wrote:
> On 05/16/2013 08:12 AM, Venu Byravarasu wrote:
>> This patch updates all Tegra board files so that they contain all the
>> properties required by the updated USB DT binding. Note that this patch
>> only adds the new properties and does not yet remove the old properties,
>> in order to maintain bisectability. The old properties will be removed
>> once the driver has been updated to assume the new bindings.
>
> This series looks almost OK now. The one remaining issue is that in this
> patch, the regulator-name properties don't match the schematics, and in
> the Whistler patch below, both regulators you added have the same
> regulator-name, which causes problems.
>
> To fix this, when I apply this patch, I'm going to fold in the patch
> I'll paste below.
>
> Right now, I can't get Whistler to see the SD card. This is true even
> without your patches. Once I've resolved that and tested Whistler,
> assuming no more problems, I'll apply patches 1-3 to the Tegra tree, and
> set up a branch that can be pulled into the USB tree so the rest of the
> series can be applied there.

I've made Whistler boot by reverting a few commits entirely unrelated to
USB or your patch series. I'll investigate those later, but for not your
patches test out fine on Whistler. So, I'll apply patches 1-3 in the
series and set up the pull request for the USB tree. Thanks.