1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 6ee7ef7..14c1f35 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -322,33 +322,6 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
free_dma_aligned_buffer(urb);
}
-static int setup_vbus_gpio(struct platform_device *pdev,
- struct tegra_ehci_platform_data *pdata)
-{
- int err = 0;
- int gpio;
-
- gpio = pdata->vbus_gpio;
- if (!gpio_is_valid(gpio))
- gpio = of_get_named_gpio(pdev->dev.of_node,
- "nvidia,vbus-gpio", 0);
- if (!gpio_is_valid(gpio))
- return 0;
-
- err = gpio_request(gpio, "vbus_gpio");
- if (err) {
- dev_err(&pdev->dev, "can't request vbus gpio %d", gpio);
- return err;
- }
- err = gpio_direction_output(gpio, 1);
- if (err) {
- dev_err(&pdev->dev, "can't enable vbus\n");
- return err;
- }
-
- return err;
-}
-
static int tegra_ehci_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -376,14 +349,11 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!pdev->dev.coherent_dma_mask)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- setup_vbus_gpio(pdev, pdata);
-
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_vbus_gpio;
+ return -ENOMEM;
}
platform_set_drvdata(pdev, hcd);
ehci = hcd_to_ehci(hcd);
@@ -494,8 +464,6 @@ cleanup_clk_get:
clk_put(tegra->clk);
cleanup_hcd_create:
usb_put_hcd(hcd);
-cleanup_vbus_gpio:
- /* FIXME: Undo setup_vbus_gpio() here */
return err;
}
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index cec0855..b3b4809 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -34,6 +34,7 @@
#include <asm/mach-types.h>
#include <linux/usb/ehci_def.h>
#include <linux/usb/tegra_usb_phy.h>
+#include <linux/regulator/consumer.h>
#define ULPI_VIEWPORT 0x170
@@ -237,12 +238,24 @@ static int utmip_pad_open(struct tegra_usb_phy *phy)
return PTR_ERR(phy->pad_clk);
}
+ phy->vbus = devm_regulator_get(phy->dev, "vbus");
+ /* On some boards, the VBUS regulator doesn't need to be controlled */
+ if (IS_ERR(phy->vbus)) {
+ if (PTR_ERR(phy->vbus) == -ENODEV) {
+ dev_notice(phy->dev, "no vbus regulator");
+ phy->vbus = NULL;
+ } else {
+ return PTR_ERR(phy->vbus);
+ }
+ }
+
return 0;
}
static void utmip_pad_power_on(struct tegra_usb_phy *phy)
{
unsigned long val, flags;
+ int err;
void __iomem *base = phy->pad_regs;
clk_prepare_enable(phy->pad_clk);
@@ -258,6 +271,14 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
spin_unlock_irqrestore(&utmip_pad_lock, flags);
clk_disable_unprepare(phy->pad_clk);
+
+ if (phy->vbus) {
+ err = regulator_enable(phy->vbus);
+ if (err)
+ dev_err(phy->dev,
+ "failed to enable usb vbus regulator: %d\n",
+ err);
+ }
}
static int utmip_pad_power_off(struct tegra_usb_phy *phy)
@@ -284,6 +305,9 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
clk_disable_unprepare(phy->pad_clk);
+ if (phy->vbus)
+ regulator_disable(phy->vbus);
+
return 0;
}
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index d2ca919..2b5fa94 100644
--- a/include/linux/usb/tegra_usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -55,6 +55,7 @@ struct tegra_usb_phy {
struct clk *clk;
struct clk *pll_u;
struct clk *pad_clk;
+ struct regulator *vbus;
enum tegra_usb_phy_mode mode;
void *config;
struct usb_phy *ulpi;
|