diff options
| -rw-r--r-- | Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt | 3 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt | 17 | ||||
| -rw-r--r-- | arch/arm/boot/dts/tegra20-harmony.dts | 4 | ||||
| -rw-r--r-- | arch/arm/boot/dts/tegra20-paz00.dts | 4 | ||||
| -rw-r--r-- | arch/arm/boot/dts/tegra20-seaboard.dts | 4 | ||||
| -rw-r--r-- | arch/arm/boot/dts/tegra20-trimslice.dts | 4 | ||||
| -rw-r--r-- | arch/arm/boot/dts/tegra20-ventana.dts | 4 | ||||
| -rw-r--r-- | arch/arm/boot/dts/tegra20.dtsi | 29 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/board-dt-tegra20.c | 6 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/iomap.h | 9 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-tegra.c | 97 | ||||
| -rw-r--r-- | drivers/usb/phy/tegra_usb_phy.c | 132 | ||||
| -rw-r--r-- | include/linux/usb/tegra_usb_phy.h | 16 |
13 files changed, 191 insertions, 138 deletions
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index e9b005dc7625..34c952883276 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt | |||
| @@ -11,6 +11,7 @@ Required properties : | |||
| 11 | - phy_type : Should be one of "ulpi" or "utmi". | 11 | - phy_type : Should be one of "ulpi" or "utmi". |
| 12 | - nvidia,vbus-gpio : If present, specifies a gpio that needs to be | 12 | - nvidia,vbus-gpio : If present, specifies a gpio that needs to be |
| 13 | activated for the bus to be powered. | 13 | activated for the bus to be powered. |
| 14 | - nvidia,phy : phandle of the PHY instance, the controller is connected to. | ||
| 14 | 15 | ||
| 15 | Required properties for phy_type == ulpi: | 16 | Required properties for phy_type == ulpi: |
| 16 | - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. | 17 | - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. |
| @@ -27,3 +28,5 @@ Optional properties: | |||
| 27 | registers are accessed through the APB_MISC base address instead of | 28 | registers are accessed through the APB_MISC base address instead of |
| 28 | the USB controller. Since this is a legacy issue it probably does not | 29 | the USB controller. Since this is a legacy issue it probably does not |
| 29 | warrant a compatible string of its own. | 30 | warrant a compatible string of its own. |
| 31 | - nvidia,needs-double-reset : boolean is to be set for some of the Tegra2 | ||
| 32 | 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 new file mode 100644 index 000000000000..6bdaba2f0aa1 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | Tegra SOC USB PHY | ||
| 2 | |||
| 3 | The device node for Tegra SOC USB PHY: | ||
| 4 | |||
| 5 | Required properties : | ||
| 6 | - compatible : Should be "nvidia,tegra20-usb-phy". | ||
| 7 | - reg : Address and length of the register set for the USB PHY interface. | ||
| 8 | - phy_type : Should be one of "ulpi" or "utmi". | ||
| 9 | |||
| 10 | Required properties for phy_type == ulpi: | ||
| 11 | - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. | ||
| 12 | |||
| 13 | Optional properties: | ||
| 14 | - nvidia,has-legacy-mode : boolean indicates whether this controller can | ||
| 15 | operate in legacy mode (as APX 2500 / 2600). In legacy mode some | ||
| 16 | registers are accessed through the APB_MISC base address instead of | ||
| 17 | the USB controller. \ No newline at end of file | ||
diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index 43eb72af8948..2b4169702c8d 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts | |||
| @@ -432,6 +432,10 @@ | |||
| 432 | status = "okay"; | 432 | status = "okay"; |
| 433 | }; | 433 | }; |
| 434 | 434 | ||
| 435 | usb-phy@c5004400 { | ||
| 436 | nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ | ||
| 437 | }; | ||
| 438 | |||
| 435 | sdhci@c8000200 { | 439 | sdhci@c8000200 { |
| 436 | status = "okay"; | 440 | status = "okay"; |
| 437 | cd-gpios = <&gpio 69 0>; /* gpio PI5 */ | 441 | cd-gpios = <&gpio 69 0>; /* gpio PI5 */ |
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index a965fe9c7aa1..11b30db63ff2 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts | |||
| @@ -420,6 +420,10 @@ | |||
| 420 | status = "okay"; | 420 | status = "okay"; |
| 421 | }; | 421 | }; |
| 422 | 422 | ||
| 423 | usb-phy@c5004400 { | ||
| 424 | nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ | ||
| 425 | }; | ||
| 426 | |||
| 423 | sdhci@c8000000 { | 427 | sdhci@c8000000 { |
| 424 | status = "okay"; | 428 | status = "okay"; |
| 425 | cd-gpios = <&gpio 173 0>; /* gpio PV5 */ | 429 | cd-gpios = <&gpio 173 0>; /* gpio PV5 */ |
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index 420459825b46..607bf0c6bf9c 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts | |||
| @@ -561,6 +561,10 @@ | |||
| 561 | status = "okay"; | 561 | status = "okay"; |
| 562 | }; | 562 | }; |
| 563 | 563 | ||
| 564 | usb-phy@c5004400 { | ||
| 565 | nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ | ||
| 566 | }; | ||
| 567 | |||
| 564 | sdhci@c8000000 { | 568 | sdhci@c8000000 { |
| 565 | status = "okay"; | 569 | status = "okay"; |
| 566 | power-gpios = <&gpio 86 0>; /* gpio PK6 */ | 570 | power-gpios = <&gpio 86 0>; /* gpio PK6 */ |
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index b70b4cb754c8..e47cf6a58b6f 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts | |||
| @@ -310,6 +310,10 @@ | |||
| 310 | status = "okay"; | 310 | status = "okay"; |
| 311 | }; | 311 | }; |
| 312 | 312 | ||
| 313 | usb-phy@c5004400 { | ||
| 314 | nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ | ||
| 315 | }; | ||
| 316 | |||
| 313 | sdhci@c8000000 { | 317 | sdhci@c8000000 { |
| 314 | status = "okay"; | 318 | status = "okay"; |
| 315 | bus-width = <4>; | 319 | bus-width = <4>; |
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index adc47547eaae..f6c61d10fd27 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts | |||
| @@ -497,6 +497,10 @@ | |||
| 497 | status = "okay"; | 497 | status = "okay"; |
| 498 | }; | 498 | }; |
| 499 | 499 | ||
| 500 | usb-phy@c5004400 { | ||
| 501 | nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ | ||
| 502 | }; | ||
| 503 | |||
| 500 | sdhci@c8000000 { | 504 | sdhci@c8000000 { |
| 501 | status = "okay"; | 505 | status = "okay"; |
| 502 | power-gpios = <&gpio 86 0>; /* gpio PK6 */ | 506 | power-gpios = <&gpio 86 0>; /* gpio PK6 */ |
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index d665a67d4358..649391579871 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi | |||
| @@ -400,6 +400,31 @@ | |||
| 400 | #size-cells = <0>; | 400 | #size-cells = <0>; |
| 401 | }; | 401 | }; |
| 402 | 402 | ||
| 403 | phy1: usb-phy@c5000400 { | ||
| 404 | compatible = "nvidia,tegra20-usb-phy"; | ||
| 405 | reg = <0xc5000400 0x3c00>; | ||
| 406 | phy_type = "utmi"; | ||
| 407 | nvidia,has-legacy-mode; | ||
| 408 | clocks = <&tegra_car 22>, <&tegra_car 127>; | ||
| 409 | clock-names = "phy", "pll_u"; | ||
| 410 | }; | ||
| 411 | |||
| 412 | phy2: usb-phy@c5004400 { | ||
| 413 | compatible = "nvidia,tegra20-usb-phy"; | ||
| 414 | reg = <0xc5004400 0x3c00>; | ||
| 415 | phy_type = "ulpi"; | ||
| 416 | clocks = <&tegra_car 94>, <&tegra_car 127>; | ||
| 417 | clock-names = "phy", "pll_u"; | ||
| 418 | }; | ||
| 419 | |||
| 420 | phy3: usb-phy@c5008400 { | ||
| 421 | compatible = "nvidia,tegra20-usb-phy"; | ||
| 422 | reg = <0xc5008400 0x3C00>; | ||
| 423 | phy_type = "utmi"; | ||
| 424 | clocks = <&tegra_car 22>, <&tegra_car 127>; | ||
| 425 | clock-names = "phy", "pll_u"; | ||
| 426 | }; | ||
| 427 | |||
| 403 | usb@c5000000 { | 428 | usb@c5000000 { |
| 404 | compatible = "nvidia,tegra20-ehci", "usb-ehci"; | 429 | compatible = "nvidia,tegra20-ehci", "usb-ehci"; |
| 405 | reg = <0xc5000000 0x4000>; | 430 | reg = <0xc5000000 0x4000>; |
| @@ -407,6 +432,8 @@ | |||
| 407 | phy_type = "utmi"; | 432 | phy_type = "utmi"; |
| 408 | nvidia,has-legacy-mode; | 433 | nvidia,has-legacy-mode; |
| 409 | clocks = <&tegra_car 22>; | 434 | clocks = <&tegra_car 22>; |
| 435 | nvidia,needs-double-reset; | ||
| 436 | nvidia,phy = <&phy1>; | ||
| 410 | status = "disabled"; | 437 | status = "disabled"; |
| 411 | }; | 438 | }; |
| 412 | 439 | ||
| @@ -416,6 +443,7 @@ | |||
| 416 | interrupts = <0 21 0x04>; | 443 | interrupts = <0 21 0x04>; |
| 417 | phy_type = "ulpi"; | 444 | phy_type = "ulpi"; |
| 418 | clocks = <&tegra_car 58>; | 445 | clocks = <&tegra_car 58>; |
| 446 | nvidia,phy = <&phy2>; | ||
| 419 | status = "disabled"; | 447 | status = "disabled"; |
| 420 | }; | 448 | }; |
| 421 | 449 | ||
| @@ -425,6 +453,7 @@ | |||
| 425 | interrupts = <0 97 0x04>; | 453 | interrupts = <0 97 0x04>; |
| 426 | phy_type = "utmi"; | 454 | phy_type = "utmi"; |
| 427 | clocks = <&tegra_car 59>; | 455 | clocks = <&tegra_car 59>; |
| 456 | nvidia,phy = <&phy3>; | ||
| 428 | status = "disabled"; | 457 | status = "disabled"; |
| 429 | }; | 458 | }; |
| 430 | 459 | ||
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index abdbe9e658f9..a0edf2510280 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c | |||
| @@ -68,11 +68,11 @@ static struct tegra_ehci_platform_data tegra_ehci3_pdata = { | |||
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { | 70 | static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { |
| 71 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0", | 71 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0", |
| 72 | &tegra_ehci1_pdata), | 72 | &tegra_ehci1_pdata), |
| 73 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1", | 73 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1", |
| 74 | &tegra_ehci2_pdata), | 74 | &tegra_ehci2_pdata), |
| 75 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", | 75 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2", |
| 76 | &tegra_ehci3_pdata), | 76 | &tegra_ehci3_pdata), |
| 77 | {} | 77 | {} |
| 78 | }; | 78 | }; |
diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index db8be51cad80..399fbca27102 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h | |||
| @@ -240,15 +240,6 @@ | |||
| 240 | #define TEGRA_CSITE_BASE 0x70040000 | 240 | #define TEGRA_CSITE_BASE 0x70040000 |
| 241 | #define TEGRA_CSITE_SIZE SZ_256K | 241 | #define TEGRA_CSITE_SIZE SZ_256K |
| 242 | 242 | ||
| 243 | #define TEGRA_USB_BASE 0xC5000000 | ||
| 244 | #define TEGRA_USB_SIZE SZ_16K | ||
| 245 | |||
| 246 | #define TEGRA_USB2_BASE 0xC5004000 | ||
| 247 | #define TEGRA_USB2_SIZE SZ_16K | ||
| 248 | |||
| 249 | #define TEGRA_USB3_BASE 0xC5008000 | ||
| 250 | #define TEGRA_USB3_SIZE SZ_16K | ||
| 251 | |||
| 252 | #define TEGRA_SDMMC1_BASE 0xC8000000 | 243 | #define TEGRA_SDMMC1_BASE 0xC8000000 |
| 253 | #define TEGRA_SDMMC1_SIZE SZ_512 | 244 | #define TEGRA_SDMMC1_SIZE SZ_512 |
| 254 | 245 | ||
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index acf17556bd87..568aecc7075b 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs | 2 | * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Google, Inc. | 4 | * Copyright (C) 2010 Google, Inc. |
| 5 | * Copyright (C) 2009 NVIDIA Corporation | 5 | * Copyright (C) 2009 - 2013 NVIDIA Corporation |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
| 8 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
| @@ -26,23 +26,28 @@ | |||
| 26 | #include <linux/of.h> | 26 | #include <linux/of.h> |
| 27 | #include <linux/of_gpio.h> | 27 | #include <linux/of_gpio.h> |
| 28 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
| 29 | 29 | #include <linux/usb/ehci_def.h> | |
| 30 | #include <linux/usb/tegra_usb_phy.h> | 30 | #include <linux/usb/tegra_usb_phy.h> |
| 31 | 31 | ||
| 32 | #define TEGRA_USB_BASE 0xC5000000 | 32 | #define TEGRA_USB_BASE 0xC5000000 |
| 33 | #define TEGRA_USB2_BASE 0xC5004000 | 33 | #define TEGRA_USB2_BASE 0xC5004000 |
| 34 | #define TEGRA_USB3_BASE 0xC5008000 | 34 | #define TEGRA_USB3_BASE 0xC5008000 |
| 35 | 35 | ||
| 36 | /* PORTSC registers */ | ||
| 37 | #define TEGRA_USB_PORTSC1 0x184 | ||
| 38 | #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) | ||
| 39 | #define TEGRA_USB_PORTSC1_PHCD (1 << 23) | ||
| 40 | |||
| 36 | #define TEGRA_USB_DMA_ALIGN 32 | 41 | #define TEGRA_USB_DMA_ALIGN 32 |
| 37 | 42 | ||
| 38 | struct tegra_ehci_hcd { | 43 | struct tegra_ehci_hcd { |
| 39 | struct ehci_hcd *ehci; | 44 | struct ehci_hcd *ehci; |
| 40 | struct tegra_usb_phy *phy; | 45 | struct tegra_usb_phy *phy; |
| 41 | struct clk *clk; | 46 | struct clk *clk; |
| 42 | struct clk *emc_clk; | ||
| 43 | struct usb_phy *transceiver; | 47 | struct usb_phy *transceiver; |
| 44 | int host_resumed; | 48 | int host_resumed; |
| 45 | int port_resuming; | 49 | int port_resuming; |
| 50 | bool needs_double_reset; | ||
| 46 | enum tegra_usb_phy_port_speed port_speed; | 51 | enum tegra_usb_phy_port_speed port_speed; |
| 47 | }; | 52 | }; |
| 48 | 53 | ||
| @@ -50,9 +55,8 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) | |||
| 50 | { | 55 | { |
| 51 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); | 56 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); |
| 52 | 57 | ||
| 53 | clk_prepare_enable(tegra->emc_clk); | ||
| 54 | clk_prepare_enable(tegra->clk); | 58 | clk_prepare_enable(tegra->clk); |
| 55 | usb_phy_set_suspend(&tegra->phy->u_phy, 0); | 59 | usb_phy_set_suspend(hcd->phy, 0); |
| 56 | tegra->host_resumed = 1; | 60 | tegra->host_resumed = 1; |
| 57 | } | 61 | } |
| 58 | 62 | ||
| @@ -61,9 +65,8 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) | |||
| 61 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); | 65 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); |
| 62 | 66 | ||
| 63 | tegra->host_resumed = 0; | 67 | tegra->host_resumed = 0; |
| 64 | usb_phy_set_suspend(&tegra->phy->u_phy, 1); | 68 | usb_phy_set_suspend(hcd->phy, 1); |
| 65 | clk_disable_unprepare(tegra->clk); | 69 | clk_disable_unprepare(tegra->clk); |
| 66 | clk_disable_unprepare(tegra->emc_clk); | ||
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | static int tegra_ehci_internal_port_reset( | 72 | static int tegra_ehci_internal_port_reset( |
| @@ -156,7 +159,7 @@ static int tegra_ehci_hub_control( | |||
| 156 | if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { | 159 | if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { |
| 157 | /* Resume completed, re-enable disconnect detection */ | 160 | /* Resume completed, re-enable disconnect detection */ |
| 158 | tegra->port_resuming = 0; | 161 | tegra->port_resuming = 0; |
| 159 | tegra_usb_phy_postresume(tegra->phy); | 162 | tegra_usb_phy_postresume(hcd->phy); |
| 160 | } | 163 | } |
| 161 | } | 164 | } |
| 162 | 165 | ||
| @@ -184,7 +187,7 @@ static int tegra_ehci_hub_control( | |||
| 184 | } | 187 | } |
| 185 | 188 | ||
| 186 | /* For USB1 port we need to issue Port Reset twice internally */ | 189 | /* For USB1 port we need to issue Port Reset twice internally */ |
| 187 | if (tegra->phy->instance == 0 && | 190 | if (tegra->needs_double_reset && |
| 188 | (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { | 191 | (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { |
| 189 | spin_unlock_irqrestore(&ehci->lock, flags); | 192 | spin_unlock_irqrestore(&ehci->lock, flags); |
| 190 | return tegra_ehci_internal_port_reset(ehci, status_reg); | 193 | return tegra_ehci_internal_port_reset(ehci, status_reg); |
| @@ -209,7 +212,7 @@ static int tegra_ehci_hub_control( | |||
| 209 | goto done; | 212 | goto done; |
| 210 | 213 | ||
| 211 | /* Disable disconnect detection during port resume */ | 214 | /* Disable disconnect detection during port resume */ |
| 212 | tegra_usb_phy_preresume(tegra->phy); | 215 | tegra_usb_phy_preresume(hcd->phy); |
| 213 | 216 | ||
| 214 | ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); | 217 | ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); |
| 215 | 218 | ||
| @@ -473,7 +476,7 @@ static int controller_resume(struct device *dev) | |||
| 473 | } | 476 | } |
| 474 | 477 | ||
| 475 | /* Force the phy to keep data lines in suspend state */ | 478 | /* Force the phy to keep data lines in suspend state */ |
| 476 | tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); | 479 | tegra_ehci_phy_restore_start(hcd->phy, tegra->port_speed); |
| 477 | 480 | ||
| 478 | /* Enable host mode */ | 481 | /* Enable host mode */ |
| 479 | tdi_reset(ehci); | 482 | tdi_reset(ehci); |
| @@ -540,17 +543,17 @@ static int controller_resume(struct device *dev) | |||
| 540 | } | 543 | } |
| 541 | } | 544 | } |
| 542 | 545 | ||
| 543 | tegra_ehci_phy_restore_end(tegra->phy); | 546 | tegra_ehci_phy_restore_end(hcd->phy); |
| 544 | goto done; | 547 | goto done; |
| 545 | 548 | ||
| 546 | restart: | 549 | restart: |
| 547 | if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) | 550 | if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) |
| 548 | tegra_ehci_phy_restore_end(tegra->phy); | 551 | tegra_ehci_phy_restore_end(hcd->phy); |
| 549 | 552 | ||
| 550 | tegra_ehci_restart(hcd); | 553 | tegra_ehci_restart(hcd); |
| 551 | 554 | ||
| 552 | done: | 555 | done: |
| 553 | tegra_usb_phy_preresume(tegra->phy); | 556 | tegra_usb_phy_preresume(hcd->phy); |
| 554 | tegra->port_resuming = 1; | 557 | tegra->port_resuming = 1; |
| 555 | return 0; | 558 | return 0; |
| 556 | } | 559 | } |
| @@ -604,6 +607,37 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = { | |||
| 604 | 607 | ||
| 605 | #endif | 608 | #endif |
| 606 | 609 | ||
| 610 | /* Bits of PORTSC1, which will get cleared by writing 1 into them */ | ||
| 611 | #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) | ||
| 612 | |||
| 613 | void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) | ||
| 614 | { | ||
| 615 | unsigned long val; | ||
| 616 | struct usb_hcd *hcd = bus_to_hcd(x->otg->host); | ||
| 617 | void __iomem *base = hcd->regs; | ||
| 618 | |||
| 619 | val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; | ||
| 620 | val &= ~TEGRA_USB_PORTSC1_PTS(3); | ||
| 621 | val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); | ||
| 622 | writel(val, base + TEGRA_USB_PORTSC1); | ||
| 623 | } | ||
| 624 | EXPORT_SYMBOL_GPL(tegra_ehci_set_pts); | ||
| 625 | |||
| 626 | void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) | ||
| 627 | { | ||
| 628 | unsigned long val; | ||
| 629 | struct usb_hcd *hcd = bus_to_hcd(x->otg->host); | ||
| 630 | void __iomem *base = hcd->regs; | ||
| 631 | |||
| 632 | val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; | ||
| 633 | if (enable) | ||
| 634 | val |= TEGRA_USB_PORTSC1_PHCD; | ||
| 635 | else | ||
| 636 | val &= ~TEGRA_USB_PORTSC1_PHCD; | ||
| 637 | writel(val, base + TEGRA_USB_PORTSC1); | ||
| 638 | } | ||
| 639 | EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd); | ||
| 640 | |||
| 607 | static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); | 641 | static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); |
| 608 | 642 | ||
| 609 | static int tegra_ehci_probe(struct platform_device *pdev) | 643 | static int tegra_ehci_probe(struct platform_device *pdev) |
| @@ -615,6 +649,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 615 | int err = 0; | 649 | int err = 0; |
| 616 | int irq; | 650 | int irq; |
| 617 | int instance = pdev->id; | 651 | int instance = pdev->id; |
| 652 | struct usb_phy *u_phy; | ||
| 618 | 653 | ||
| 619 | pdata = pdev->dev.platform_data; | 654 | pdata = pdev->dev.platform_data; |
| 620 | if (!pdata) { | 655 | if (!pdata) { |
| @@ -656,15 +691,8 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 656 | if (err) | 691 | if (err) |
| 657 | goto fail_clk; | 692 | goto fail_clk; |
| 658 | 693 | ||
| 659 | tegra->emc_clk = devm_clk_get(&pdev->dev, "emc"); | 694 | tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, |
| 660 | if (IS_ERR(tegra->emc_clk)) { | 695 | "nvidia,needs-double-reset"); |
| 661 | dev_err(&pdev->dev, "Can't get emc clock\n"); | ||
| 662 | err = PTR_ERR(tegra->emc_clk); | ||
| 663 | goto fail_emc_clk; | ||
| 664 | } | ||
| 665 | |||
| 666 | clk_prepare_enable(tegra->emc_clk); | ||
| 667 | clk_set_rate(tegra->emc_clk, 400000000); | ||
| 668 | 696 | ||
| 669 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 697 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 670 | if (!res) { | 698 | if (!res) { |
| @@ -712,9 +740,19 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 712 | goto fail_io; | 740 | goto fail_io; |
| 713 | } | 741 | } |
| 714 | 742 | ||
| 715 | usb_phy_init(&tegra->phy->u_phy); | 743 | hcd->phy = u_phy = &tegra->phy->u_phy; |
| 744 | usb_phy_init(hcd->phy); | ||
| 745 | |||
| 746 | u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), | ||
| 747 | GFP_KERNEL); | ||
| 748 | if (!u_phy->otg) { | ||
| 749 | dev_err(&pdev->dev, "Failed to alloc memory for otg\n"); | ||
| 750 | err = -ENOMEM; | ||
| 751 | goto fail_io; | ||
| 752 | } | ||
| 753 | u_phy->otg->host = hcd_to_bus(hcd); | ||
| 716 | 754 | ||
| 717 | err = usb_phy_set_suspend(&tegra->phy->u_phy, 0); | 755 | err = usb_phy_set_suspend(hcd->phy, 0); |
| 718 | if (err) { | 756 | if (err) { |
| 719 | dev_err(&pdev->dev, "Failed to power on the phy\n"); | 757 | dev_err(&pdev->dev, "Failed to power on the phy\n"); |
| 720 | goto fail; | 758 | goto fail; |
| @@ -760,10 +798,8 @@ fail: | |||
| 760 | if (!IS_ERR_OR_NULL(tegra->transceiver)) | 798 | if (!IS_ERR_OR_NULL(tegra->transceiver)) |
| 761 | otg_set_host(tegra->transceiver->otg, NULL); | 799 | otg_set_host(tegra->transceiver->otg, NULL); |
| 762 | #endif | 800 | #endif |
| 763 | usb_phy_shutdown(&tegra->phy->u_phy); | 801 | usb_phy_shutdown(hcd->phy); |
| 764 | fail_io: | 802 | fail_io: |
| 765 | clk_disable_unprepare(tegra->emc_clk); | ||
| 766 | fail_emc_clk: | ||
| 767 | clk_disable_unprepare(tegra->clk); | 803 | clk_disable_unprepare(tegra->clk); |
| 768 | fail_clk: | 804 | fail_clk: |
| 769 | usb_put_hcd(hcd); | 805 | usb_put_hcd(hcd); |
| @@ -784,15 +820,12 @@ static int tegra_ehci_remove(struct platform_device *pdev) | |||
| 784 | otg_set_host(tegra->transceiver->otg, NULL); | 820 | otg_set_host(tegra->transceiver->otg, NULL); |
| 785 | #endif | 821 | #endif |
| 786 | 822 | ||
| 823 | usb_phy_shutdown(hcd->phy); | ||
| 787 | usb_remove_hcd(hcd); | 824 | usb_remove_hcd(hcd); |
| 788 | usb_put_hcd(hcd); | 825 | usb_put_hcd(hcd); |
| 789 | 826 | ||
| 790 | usb_phy_shutdown(&tegra->phy->u_phy); | ||
| 791 | |||
| 792 | clk_disable_unprepare(tegra->clk); | 827 | clk_disable_unprepare(tegra->clk); |
| 793 | 828 | ||
| 794 | clk_disable_unprepare(tegra->emc_clk); | ||
| 795 | |||
| 796 | return 0; | 829 | return 0; |
| 797 | } | 830 | } |
| 798 | 831 | ||
diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 9d13c81754e0..5487d38481af 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| 26 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
| 27 | #include <linux/of.h> | ||
| 27 | #include <linux/of_gpio.h> | 28 | #include <linux/of_gpio.h> |
| 28 | #include <linux/usb/otg.h> | 29 | #include <linux/usb/otg.h> |
| 29 | #include <linux/usb/ulpi.h> | 30 | #include <linux/usb/ulpi.h> |
| @@ -35,19 +36,6 @@ | |||
| 35 | 36 | ||
| 36 | #define ULPI_VIEWPORT 0x170 | 37 | #define ULPI_VIEWPORT 0x170 |
| 37 | 38 | ||
| 38 | #define USB_PORTSC1 0x184 | ||
| 39 | #define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) | ||
| 40 | #define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26) | ||
| 41 | #define USB_PORTSC1_PHCD (1 << 23) | ||
| 42 | #define USB_PORTSC1_WKOC (1 << 22) | ||
| 43 | #define USB_PORTSC1_WKDS (1 << 21) | ||
| 44 | #define USB_PORTSC1_WKCN (1 << 20) | ||
| 45 | #define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) | ||
| 46 | #define USB_PORTSC1_PP (1 << 12) | ||
| 47 | #define USB_PORTSC1_SUSP (1 << 7) | ||
| 48 | #define USB_PORTSC1_PE (1 << 2) | ||
| 49 | #define USB_PORTSC1_CCS (1 << 0) | ||
| 50 | |||
| 51 | #define USB_SUSP_CTRL 0x400 | 39 | #define USB_SUSP_CTRL 0x400 |
| 52 | #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) | 40 | #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) |
| 53 | #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) | 41 | #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) |
| @@ -208,11 +196,6 @@ static struct tegra_utmip_config utmip_default[] = { | |||
| 208 | }, | 196 | }, |
| 209 | }; | 197 | }; |
| 210 | 198 | ||
| 211 | static inline bool phy_is_ulpi(struct tegra_usb_phy *phy) | ||
| 212 | { | ||
| 213 | return (phy->instance == 1); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int utmip_pad_open(struct tegra_usb_phy *phy) | 199 | static int utmip_pad_open(struct tegra_usb_phy *phy) |
| 217 | { | 200 | { |
| 218 | phy->pad_clk = clk_get_sys("utmip-pad", NULL); | 201 | phy->pad_clk = clk_get_sys("utmip-pad", NULL); |
| @@ -221,7 +204,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) | |||
| 221 | return PTR_ERR(phy->pad_clk); | 204 | return PTR_ERR(phy->pad_clk); |
| 222 | } | 205 | } |
| 223 | 206 | ||
| 224 | if (phy->instance == 0) { | 207 | if (phy->is_legacy_phy) { |
| 225 | phy->pad_regs = phy->regs; | 208 | phy->pad_regs = phy->regs; |
| 226 | } else { | 209 | } else { |
| 227 | phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); | 210 | phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); |
| @@ -236,7 +219,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) | |||
| 236 | 219 | ||
| 237 | static void utmip_pad_close(struct tegra_usb_phy *phy) | 220 | static void utmip_pad_close(struct tegra_usb_phy *phy) |
| 238 | { | 221 | { |
| 239 | if (phy->instance != 0) | 222 | if (!phy->is_legacy_phy) |
| 240 | iounmap(phy->pad_regs); | 223 | iounmap(phy->pad_regs); |
| 241 | clk_put(phy->pad_clk); | 224 | clk_put(phy->pad_clk); |
| 242 | } | 225 | } |
| @@ -305,7 +288,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) | |||
| 305 | unsigned long val; | 288 | unsigned long val; |
| 306 | void __iomem *base = phy->regs; | 289 | void __iomem *base = phy->regs; |
| 307 | 290 | ||
| 308 | if (phy->instance == 0) { | 291 | if (phy->is_legacy_phy) { |
| 309 | val = readl(base + USB_SUSP_CTRL); | 292 | val = readl(base + USB_SUSP_CTRL); |
| 310 | val |= USB_SUSP_SET; | 293 | val |= USB_SUSP_SET; |
| 311 | writel(val, base + USB_SUSP_CTRL); | 294 | writel(val, base + USB_SUSP_CTRL); |
| @@ -315,13 +298,8 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) | |||
| 315 | val = readl(base + USB_SUSP_CTRL); | 298 | val = readl(base + USB_SUSP_CTRL); |
| 316 | val &= ~USB_SUSP_SET; | 299 | val &= ~USB_SUSP_SET; |
| 317 | writel(val, base + USB_SUSP_CTRL); | 300 | writel(val, base + USB_SUSP_CTRL); |
| 318 | } | 301 | } else |
| 319 | 302 | tegra_ehci_set_phcd(&phy->u_phy, true); | |
| 320 | if (phy->instance == 2) { | ||
| 321 | val = readl(base + USB_PORTSC1); | ||
| 322 | val |= USB_PORTSC1_PHCD; | ||
| 323 | writel(val, base + USB_PORTSC1); | ||
| 324 | } | ||
| 325 | 303 | ||
| 326 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) | 304 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) |
| 327 | pr_err("%s: timeout waiting for phy to stabilize\n", __func__); | 305 | pr_err("%s: timeout waiting for phy to stabilize\n", __func__); |
| @@ -332,7 +310,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) | |||
| 332 | unsigned long val; | 310 | unsigned long val; |
| 333 | void __iomem *base = phy->regs; | 311 | void __iomem *base = phy->regs; |
| 334 | 312 | ||
| 335 | if (phy->instance == 0) { | 313 | if (phy->is_legacy_phy) { |
| 336 | val = readl(base + USB_SUSP_CTRL); | 314 | val = readl(base + USB_SUSP_CTRL); |
| 337 | val |= USB_SUSP_CLR; | 315 | val |= USB_SUSP_CLR; |
| 338 | writel(val, base + USB_SUSP_CTRL); | 316 | writel(val, base + USB_SUSP_CTRL); |
| @@ -342,13 +320,8 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) | |||
| 342 | val = readl(base + USB_SUSP_CTRL); | 320 | val = readl(base + USB_SUSP_CTRL); |
| 343 | val &= ~USB_SUSP_CLR; | 321 | val &= ~USB_SUSP_CLR; |
| 344 | writel(val, base + USB_SUSP_CTRL); | 322 | writel(val, base + USB_SUSP_CTRL); |
| 345 | } | 323 | } else |
| 346 | 324 | tegra_ehci_set_phcd(&phy->u_phy, false); | |
| 347 | if (phy->instance == 2) { | ||
| 348 | val = readl(base + USB_PORTSC1); | ||
| 349 | val &= ~USB_PORTSC1_PHCD; | ||
| 350 | writel(val, base + USB_PORTSC1); | ||
| 351 | } | ||
| 352 | 325 | ||
| 353 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, | 326 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, |
| 354 | USB_PHY_CLK_VALID)) | 327 | USB_PHY_CLK_VALID)) |
| @@ -365,7 +338,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 365 | val |= UTMIP_RESET; | 338 | val |= UTMIP_RESET; |
| 366 | writel(val, base + USB_SUSP_CTRL); | 339 | writel(val, base + USB_SUSP_CTRL); |
| 367 | 340 | ||
| 368 | if (phy->instance == 0) { | 341 | if (phy->is_legacy_phy) { |
| 369 | val = readl(base + USB1_LEGACY_CTRL); | 342 | val = readl(base + USB1_LEGACY_CTRL); |
| 370 | val |= USB1_NO_LEGACY_MODE; | 343 | val |= USB1_NO_LEGACY_MODE; |
| 371 | writel(val, base + USB1_LEGACY_CTRL); | 344 | writel(val, base + USB1_LEGACY_CTRL); |
| @@ -440,16 +413,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 440 | val |= UTMIP_BIAS_PDTRK_COUNT(0x5); | 413 | val |= UTMIP_BIAS_PDTRK_COUNT(0x5); |
| 441 | writel(val, base + UTMIP_BIAS_CFG1); | 414 | writel(val, base + UTMIP_BIAS_CFG1); |
| 442 | 415 | ||
| 443 | if (phy->instance == 0) { | 416 | if (phy->is_legacy_phy) { |
| 444 | val = readl(base + UTMIP_SPARE_CFG0); | 417 | val = readl(base + UTMIP_SPARE_CFG0); |
| 445 | if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) | 418 | if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) |
| 446 | val &= ~FUSE_SETUP_SEL; | 419 | val &= ~FUSE_SETUP_SEL; |
| 447 | else | 420 | else |
| 448 | val |= FUSE_SETUP_SEL; | 421 | val |= FUSE_SETUP_SEL; |
| 449 | writel(val, base + UTMIP_SPARE_CFG0); | 422 | writel(val, base + UTMIP_SPARE_CFG0); |
| 450 | } | 423 | } else { |
| 451 | |||
| 452 | if (phy->instance == 2) { | ||
| 453 | val = readl(base + USB_SUSP_CTRL); | 424 | val = readl(base + USB_SUSP_CTRL); |
| 454 | val |= UTMIP_PHY_ENABLE; | 425 | val |= UTMIP_PHY_ENABLE; |
| 455 | writel(val, base + USB_SUSP_CTRL); | 426 | writel(val, base + USB_SUSP_CTRL); |
| @@ -459,7 +430,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 459 | val &= ~UTMIP_RESET; | 430 | val &= ~UTMIP_RESET; |
| 460 | writel(val, base + USB_SUSP_CTRL); | 431 | writel(val, base + USB_SUSP_CTRL); |
| 461 | 432 | ||
| 462 | if (phy->instance == 0) { | 433 | if (phy->is_legacy_phy) { |
| 463 | val = readl(base + USB1_LEGACY_CTRL); | 434 | val = readl(base + USB1_LEGACY_CTRL); |
| 464 | val &= ~USB1_VBUS_SENSE_CTL_MASK; | 435 | val &= ~USB1_VBUS_SENSE_CTL_MASK; |
| 465 | val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; | 436 | val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; |
| @@ -472,11 +443,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 472 | 443 | ||
| 473 | utmi_phy_clk_enable(phy); | 444 | utmi_phy_clk_enable(phy); |
| 474 | 445 | ||
| 475 | if (phy->instance == 2) { | 446 | if (!phy->is_legacy_phy) |
| 476 | val = readl(base + USB_PORTSC1); | 447 | tegra_ehci_set_pts(&phy->u_phy, 0); |
| 477 | val &= ~USB_PORTSC1_PTS(~0); | ||
| 478 | writel(val, base + USB_PORTSC1); | ||
| 479 | } | ||
| 480 | 448 | ||
| 481 | return 0; | 449 | return 0; |
| 482 | } | 450 | } |
| @@ -621,10 +589,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 621 | return ret; | 589 | return ret; |
| 622 | } | 590 | } |
| 623 | 591 | ||
| 624 | val = readl(base + USB_PORTSC1); | ||
| 625 | val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; | ||
| 626 | writel(val, base + USB_PORTSC1); | ||
| 627 | |||
| 628 | val = readl(base + USB_SUSP_CTRL); | 592 | val = readl(base + USB_SUSP_CTRL); |
| 629 | val |= USB_SUSP_CLR; | 593 | val |= USB_SUSP_CLR; |
| 630 | writel(val, base + USB_SUSP_CTRL); | 594 | writel(val, base + USB_SUSP_CTRL); |
| @@ -639,17 +603,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 639 | 603 | ||
| 640 | static int ulpi_phy_power_off(struct tegra_usb_phy *phy) | 604 | static int ulpi_phy_power_off(struct tegra_usb_phy *phy) |
| 641 | { | 605 | { |
| 642 | unsigned long val; | ||
| 643 | void __iomem *base = phy->regs; | ||
| 644 | struct tegra_ulpi_config *config = phy->config; | 606 | struct tegra_ulpi_config *config = phy->config; |
| 645 | 607 | ||
| 646 | /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB | ||
| 647 | * Controller to immediately bring the ULPI PHY out of low power | ||
| 648 | */ | ||
| 649 | val = readl(base + USB_PORTSC1); | ||
| 650 | val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); | ||
| 651 | writel(val, base + USB_PORTSC1); | ||
| 652 | |||
| 653 | clk_disable(phy->clk); | 608 | clk_disable(phy->clk); |
| 654 | return gpio_direction_output(config->reset_gpio, 0); | 609 | return gpio_direction_output(config->reset_gpio, 0); |
| 655 | } | 610 | } |
| @@ -660,7 +615,7 @@ static int tegra_phy_init(struct usb_phy *x) | |||
| 660 | struct tegra_ulpi_config *ulpi_config; | 615 | struct tegra_ulpi_config *ulpi_config; |
| 661 | int err; | 616 | int err; |
| 662 | 617 | ||
| 663 | if (phy_is_ulpi(phy)) { | 618 | if (phy->is_ulpi_phy) { |
| 664 | ulpi_config = phy->config; | 619 | ulpi_config = phy->config; |
| 665 | phy->clk = clk_get_sys(NULL, ulpi_config->clk); | 620 | phy->clk = clk_get_sys(NULL, ulpi_config->clk); |
| 666 | if (IS_ERR(phy->clk)) { | 621 | if (IS_ERR(phy->clk)) { |
| @@ -698,7 +653,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) | |||
| 698 | { | 653 | { |
| 699 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); | 654 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 700 | 655 | ||
| 701 | if (phy_is_ulpi(phy)) | 656 | if (phy->is_ulpi_phy) |
| 702 | clk_put(phy->clk); | 657 | clk_put(phy->clk); |
| 703 | else | 658 | else |
| 704 | utmip_pad_close(phy); | 659 | utmip_pad_close(phy); |
| @@ -709,7 +664,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) | |||
| 709 | 664 | ||
| 710 | static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) | 665 | static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) |
| 711 | { | 666 | { |
| 712 | if (phy_is_ulpi(phy)) | 667 | if (phy->is_ulpi_phy) |
| 713 | return ulpi_phy_power_on(phy); | 668 | return ulpi_phy_power_on(phy); |
| 714 | else | 669 | else |
| 715 | return utmi_phy_power_on(phy); | 670 | return utmi_phy_power_on(phy); |
| @@ -717,7 +672,7 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) | |||
| 717 | 672 | ||
| 718 | static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) | 673 | static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) |
| 719 | { | 674 | { |
| 720 | if (phy_is_ulpi(phy)) | 675 | if (phy->is_ulpi_phy) |
| 721 | return ulpi_phy_power_off(phy); | 676 | return ulpi_phy_power_off(phy); |
| 722 | else | 677 | else |
| 723 | return utmi_phy_power_off(phy); | 678 | return utmi_phy_power_off(phy); |
| @@ -739,8 +694,9 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | |||
| 739 | unsigned long parent_rate; | 694 | unsigned long parent_rate; |
| 740 | int i; | 695 | int i; |
| 741 | int err; | 696 | int err; |
| 697 | struct device_node *np = dev->of_node; | ||
| 742 | 698 | ||
| 743 | phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); | 699 | phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); |
| 744 | if (!phy) | 700 | if (!phy) |
| 745 | return ERR_PTR(-ENOMEM); | 701 | return ERR_PTR(-ENOMEM); |
| 746 | 702 | ||
| @@ -749,9 +705,16 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | |||
| 749 | phy->config = config; | 705 | phy->config = config; |
| 750 | phy->mode = phy_mode; | 706 | phy->mode = phy_mode; |
| 751 | phy->dev = dev; | 707 | phy->dev = dev; |
| 708 | phy->is_legacy_phy = | ||
| 709 | of_property_read_bool(np, "nvidia,has-legacy-mode"); | ||
| 710 | err = of_property_match_string(np, "phy_type", "ulpi"); | ||
| 711 | if (err < 0) | ||
| 712 | phy->is_ulpi_phy = false; | ||
| 713 | else | ||
| 714 | phy->is_ulpi_phy = true; | ||
| 752 | 715 | ||
| 753 | if (!phy->config) { | 716 | if (!phy->config) { |
| 754 | if (phy_is_ulpi(phy)) { | 717 | if (phy->is_ulpi_phy) { |
| 755 | pr_err("%s: ulpi phy configuration missing", __func__); | 718 | pr_err("%s: ulpi phy configuration missing", __func__); |
| 756 | err = -EINVAL; | 719 | err = -EINVAL; |
| 757 | goto err0; | 720 | goto err0; |
| @@ -796,45 +759,40 @@ err0: | |||
| 796 | } | 759 | } |
| 797 | EXPORT_SYMBOL_GPL(tegra_usb_phy_open); | 760 | EXPORT_SYMBOL_GPL(tegra_usb_phy_open); |
| 798 | 761 | ||
| 799 | void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) | 762 | void tegra_usb_phy_preresume(struct usb_phy *x) |
| 800 | { | 763 | { |
| 801 | if (!phy_is_ulpi(phy)) | 764 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 765 | |||
| 766 | if (!phy->is_ulpi_phy) | ||
| 802 | utmi_phy_preresume(phy); | 767 | utmi_phy_preresume(phy); |
| 803 | } | 768 | } |
| 804 | EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); | 769 | EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); |
| 805 | 770 | ||
| 806 | void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) | 771 | void tegra_usb_phy_postresume(struct usb_phy *x) |
| 807 | { | 772 | { |
| 808 | if (!phy_is_ulpi(phy)) | 773 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 774 | |||
| 775 | if (!phy->is_ulpi_phy) | ||
| 809 | utmi_phy_postresume(phy); | 776 | utmi_phy_postresume(phy); |
| 810 | } | 777 | } |
| 811 | EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); | 778 | EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); |
| 812 | 779 | ||
| 813 | void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, | 780 | void tegra_ehci_phy_restore_start(struct usb_phy *x, |
| 814 | enum tegra_usb_phy_port_speed port_speed) | 781 | enum tegra_usb_phy_port_speed port_speed) |
| 815 | { | 782 | { |
| 816 | if (!phy_is_ulpi(phy)) | 783 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 784 | |||
| 785 | if (!phy->is_ulpi_phy) | ||
| 817 | utmi_phy_restore_start(phy, port_speed); | 786 | utmi_phy_restore_start(phy, port_speed); |
| 818 | } | 787 | } |
| 819 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); | 788 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); |
| 820 | 789 | ||
| 821 | void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) | 790 | void tegra_ehci_phy_restore_end(struct usb_phy *x) |
| 822 | { | 791 | { |
| 823 | if (!phy_is_ulpi(phy)) | 792 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 793 | |||
| 794 | if (!phy->is_ulpi_phy) | ||
| 824 | utmi_phy_restore_end(phy); | 795 | utmi_phy_restore_end(phy); |
| 825 | } | 796 | } |
| 826 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); | 797 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); |
| 827 | 798 | ||
| 828 | void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) | ||
| 829 | { | ||
| 830 | if (!phy_is_ulpi(phy)) | ||
| 831 | utmi_phy_clk_disable(phy); | ||
| 832 | } | ||
| 833 | EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable); | ||
| 834 | |||
| 835 | void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) | ||
| 836 | { | ||
| 837 | if (!phy_is_ulpi(phy)) | ||
| 838 | utmi_phy_clk_enable(phy); | ||
| 839 | } | ||
| 840 | EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable); | ||
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 176b1ca06ae4..9ebebe906925 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h | |||
| @@ -59,22 +59,24 @@ struct tegra_usb_phy { | |||
| 59 | struct usb_phy *ulpi; | 59 | struct usb_phy *ulpi; |
| 60 | struct usb_phy u_phy; | 60 | struct usb_phy u_phy; |
| 61 | struct device *dev; | 61 | struct device *dev; |
| 62 | bool is_legacy_phy; | ||
| 63 | bool is_ulpi_phy; | ||
| 62 | }; | 64 | }; |
| 63 | 65 | ||
| 64 | struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | 66 | struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, |
| 65 | void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode); | 67 | void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode); |
| 66 | 68 | ||
| 67 | void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy); | 69 | void tegra_usb_phy_preresume(struct usb_phy *phy); |
| 68 | 70 | ||
| 69 | void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); | 71 | void tegra_usb_phy_postresume(struct usb_phy *phy); |
| 70 | 72 | ||
| 71 | void tegra_usb_phy_preresume(struct tegra_usb_phy *phy); | 73 | void tegra_ehci_phy_restore_start(struct usb_phy *phy, |
| 74 | enum tegra_usb_phy_port_speed port_speed); | ||
| 72 | 75 | ||
| 73 | void tegra_usb_phy_postresume(struct tegra_usb_phy *phy); | 76 | void tegra_ehci_phy_restore_end(struct usb_phy *phy); |
| 74 | 77 | ||
| 75 | void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, | 78 | void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val); |
| 76 | enum tegra_usb_phy_port_speed port_speed); | ||
| 77 | 79 | ||
| 78 | void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); | 80 | void tegra_ehci_set_phcd(struct usb_phy *x, bool enable); |
| 79 | 81 | ||
| 80 | #endif /* __TEGRA_USB_PHY_H */ | 82 | #endif /* __TEGRA_USB_PHY_H */ |
