diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/host/ehci-omap.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/host/ehci-omap.c')
-rw-r--r-- | drivers/usb/host/ehci-omap.c | 726 |
1 files changed, 103 insertions, 623 deletions
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 116ae280053a..55a57c23dd0f 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c | |||
@@ -1,11 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * ehci-omap.c - driver for USBHOST on OMAP 34xx processor | 2 | * ehci-omap.c - driver for USBHOST on OMAP3/4 processors |
3 | * | 3 | * |
4 | * Bus Glue for OMAP34xx USBHOST 3 port EHCI controller | 4 | * Bus Glue for the EHCI controllers in OMAP3/4 |
5 | * Tested on OMAP3430 ES2.0 SDP | 5 | * Tested on several OMAP3 boards, and OMAP4 Pandaboard |
6 | * | 6 | * |
7 | * Copyright (C) 2007-2008 Texas Instruments, Inc. | 7 | * Copyright (C) 2007-2011 Texas Instruments, Inc. |
8 | * Author: Vikram Pandita <vikram.pandita@ti.com> | 8 | * Author: Vikram Pandita <vikram.pandita@ti.com> |
9 | * Author: Anand Gadiyar <gadiyar@ti.com> | ||
10 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | ||
9 | * | 11 | * |
10 | * Copyright (C) 2009 Nokia Corporation | 12 | * Copyright (C) 2009 Nokia Corporation |
11 | * Contact: Felipe Balbi <felipe.balbi@nokia.com> | 13 | * Contact: Felipe Balbi <felipe.balbi@nokia.com> |
@@ -26,95 +28,19 @@ | |||
26 | * along with this program; if not, write to the Free Software | 28 | * along with this program; if not, write to the Free Software |
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
28 | * | 30 | * |
29 | * TODO (last updated Feb 12, 2010): | 31 | * TODO (last updated Feb 27, 2010): |
30 | * - add kernel-doc | 32 | * - add kernel-doc |
31 | * - enable AUTOIDLE | 33 | * - enable AUTOIDLE |
32 | * - add suspend/resume | 34 | * - add suspend/resume |
33 | * - move workarounds to board-files | 35 | * - add HSIC and TLL support |
36 | * - convert to use hwmod and runtime PM | ||
34 | */ | 37 | */ |
35 | 38 | ||
36 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
37 | #include <linux/clk.h> | ||
38 | #include <linux/gpio.h> | ||
39 | #include <linux/regulator/consumer.h> | ||
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <linux/usb/ulpi.h> | 41 | #include <linux/usb/ulpi.h> |
42 | #include <plat/usb.h> | 42 | #include <plat/usb.h> |
43 | 43 | #include <linux/regulator/consumer.h> | |
44 | /* | ||
45 | * OMAP USBHOST Register addresses: VIRTUAL ADDRESSES | ||
46 | * Use ehci_omap_readl()/ehci_omap_writel() functions | ||
47 | */ | ||
48 | |||
49 | /* TLL Register Set */ | ||
50 | #define OMAP_USBTLL_REVISION (0x00) | ||
51 | #define OMAP_USBTLL_SYSCONFIG (0x10) | ||
52 | #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) | ||
53 | #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) | ||
54 | #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
55 | #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) | ||
56 | #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) | ||
57 | |||
58 | #define OMAP_USBTLL_SYSSTATUS (0x14) | ||
59 | #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) | ||
60 | |||
61 | #define OMAP_USBTLL_IRQSTATUS (0x18) | ||
62 | #define OMAP_USBTLL_IRQENABLE (0x1C) | ||
63 | |||
64 | #define OMAP_TLL_SHARED_CONF (0x30) | ||
65 | #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) | ||
66 | #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) | ||
67 | #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) | ||
68 | #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) | ||
69 | #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) | ||
70 | |||
71 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | ||
72 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | ||
73 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | ||
74 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | ||
75 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | ||
76 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | ||
77 | |||
78 | #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) | ||
79 | #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) | ||
80 | #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) | ||
81 | #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) | ||
82 | #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) | ||
83 | #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) | ||
84 | #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) | ||
85 | #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) | ||
86 | #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) | ||
87 | |||
88 | #define OMAP_TLL_CHANNEL_COUNT 3 | ||
89 | #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 1) | ||
90 | #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 2) | ||
91 | #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 4) | ||
92 | |||
93 | /* UHH Register Set */ | ||
94 | #define OMAP_UHH_REVISION (0x00) | ||
95 | #define OMAP_UHH_SYSCONFIG (0x10) | ||
96 | #define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12) | ||
97 | #define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8) | ||
98 | #define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3) | ||
99 | #define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
100 | #define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1) | ||
101 | #define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0) | ||
102 | |||
103 | #define OMAP_UHH_SYSSTATUS (0x14) | ||
104 | #define OMAP_UHH_HOSTCONFIG (0x40) | ||
105 | #define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0) | ||
106 | #define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0) | ||
107 | #define OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS (1 << 11) | ||
108 | #define OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS (1 << 12) | ||
109 | #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2) | ||
110 | #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3) | ||
111 | #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4) | ||
112 | #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5) | ||
113 | #define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS (1 << 8) | ||
114 | #define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9) | ||
115 | #define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10) | ||
116 | |||
117 | #define OMAP_UHH_DEBUG_CSR (0x44) | ||
118 | 44 | ||
119 | /* EHCI Register Set */ | 45 | /* EHCI Register Set */ |
120 | #define EHCI_INSNREG04 (0xA0) | 46 | #define EHCI_INSNREG04 (0xA0) |
@@ -129,116 +55,22 @@ | |||
129 | 55 | ||
130 | /*-------------------------------------------------------------------------*/ | 56 | /*-------------------------------------------------------------------------*/ |
131 | 57 | ||
132 | static inline void ehci_omap_writel(void __iomem *base, u32 reg, u32 val) | 58 | static const struct hc_driver ehci_omap_hc_driver; |
133 | { | ||
134 | __raw_writel(val, base + reg); | ||
135 | } | ||
136 | 59 | ||
137 | static inline u32 ehci_omap_readl(void __iomem *base, u32 reg) | ||
138 | { | ||
139 | return __raw_readl(base + reg); | ||
140 | } | ||
141 | 60 | ||
142 | static inline void ehci_omap_writeb(void __iomem *base, u8 reg, u8 val) | 61 | static inline void ehci_write(void __iomem *base, u32 reg, u32 val) |
143 | { | 62 | { |
144 | __raw_writeb(val, base + reg); | 63 | __raw_writel(val, base + reg); |
145 | } | 64 | } |
146 | 65 | ||
147 | static inline u8 ehci_omap_readb(void __iomem *base, u8 reg) | 66 | static inline u32 ehci_read(void __iomem *base, u32 reg) |
148 | { | 67 | { |
149 | return __raw_readb(base + reg); | 68 | return __raw_readl(base + reg); |
150 | } | ||
151 | |||
152 | /*-------------------------------------------------------------------------*/ | ||
153 | |||
154 | struct ehci_hcd_omap { | ||
155 | struct ehci_hcd *ehci; | ||
156 | struct device *dev; | ||
157 | |||
158 | struct clk *usbhost_ick; | ||
159 | struct clk *usbhost2_120m_fck; | ||
160 | struct clk *usbhost1_48m_fck; | ||
161 | struct clk *usbtll_fck; | ||
162 | struct clk *usbtll_ick; | ||
163 | |||
164 | /* FIXME the following two workarounds are | ||
165 | * board specific not silicon-specific so these | ||
166 | * should be moved to board-file instead. | ||
167 | * | ||
168 | * Maybe someone from TI will know better which | ||
169 | * board is affected and needs the workarounds | ||
170 | * to be applied | ||
171 | */ | ||
172 | |||
173 | /* gpio for resetting phy */ | ||
174 | int reset_gpio_port[OMAP3_HS_USB_PORTS]; | ||
175 | |||
176 | /* phy reset workaround */ | ||
177 | int phy_reset; | ||
178 | |||
179 | /* desired phy_mode: TLL, PHY */ | ||
180 | enum ehci_hcd_omap_mode port_mode[OMAP3_HS_USB_PORTS]; | ||
181 | |||
182 | void __iomem *uhh_base; | ||
183 | void __iomem *tll_base; | ||
184 | void __iomem *ehci_base; | ||
185 | |||
186 | /* Regulators for USB PHYs. | ||
187 | * Each PHY can have a separate regulator. | ||
188 | */ | ||
189 | struct regulator *regulator[OMAP3_HS_USB_PORTS]; | ||
190 | }; | ||
191 | |||
192 | /*-------------------------------------------------------------------------*/ | ||
193 | |||
194 | static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask) | ||
195 | { | ||
196 | unsigned reg; | ||
197 | int i; | ||
198 | |||
199 | /* Program the 3 TLL channels upfront */ | ||
200 | for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { | ||
201 | reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); | ||
202 | |||
203 | /* Disable AutoIdle, BitStuffing and use SDR Mode */ | ||
204 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | ||
205 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | ||
206 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | ||
207 | ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); | ||
208 | } | ||
209 | |||
210 | /* Program Common TLL register */ | ||
211 | reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF); | ||
212 | reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | ||
213 | | OMAP_TLL_SHARED_CONF_USB_DIVRATION | ||
214 | | OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN); | ||
215 | reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; | ||
216 | |||
217 | ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); | ||
218 | |||
219 | /* Enable channels now */ | ||
220 | for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { | ||
221 | reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); | ||
222 | |||
223 | /* Enable only the reg that is needed */ | ||
224 | if (!(tll_channel_mask & 1<<i)) | ||
225 | continue; | ||
226 | |||
227 | reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; | ||
228 | ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); | ||
229 | |||
230 | ehci_omap_writeb(omap->tll_base, | ||
231 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); | ||
232 | dev_dbg(omap->dev, "ULPI_SCRATCH_REG[ch=%d]= 0x%02x\n", | ||
233 | i+1, ehci_omap_readb(omap->tll_base, | ||
234 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i))); | ||
235 | } | ||
236 | } | 69 | } |
237 | 70 | ||
238 | /*-------------------------------------------------------------------------*/ | 71 | static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port) |
239 | |||
240 | static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port) | ||
241 | { | 72 | { |
73 | struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); | ||
242 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | 74 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); |
243 | unsigned reg = 0; | 75 | unsigned reg = 0; |
244 | 76 | ||
@@ -252,336 +84,20 @@ static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port) | |||
252 | /* start ULPI access*/ | 84 | /* start ULPI access*/ |
253 | | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); | 85 | | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); |
254 | 86 | ||
255 | ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI, reg); | 87 | ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg); |
256 | 88 | ||
257 | /* Wait for ULPI access completion */ | 89 | /* Wait for ULPI access completion */ |
258 | while ((ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI) | 90 | while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI) |
259 | & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { | 91 | & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { |
260 | cpu_relax(); | 92 | cpu_relax(); |
261 | 93 | ||
262 | if (time_after(jiffies, timeout)) { | 94 | if (time_after(jiffies, timeout)) { |
263 | dev_dbg(omap->dev, "phy reset operation timed out\n"); | 95 | dev_dbg(&pdev->dev, "phy reset operation timed out\n"); |
264 | break; | 96 | break; |
265 | } | 97 | } |
266 | } | 98 | } |
267 | } | 99 | } |
268 | 100 | ||
269 | /* omap_start_ehc | ||
270 | * - Start the TI USBHOST controller | ||
271 | */ | ||
272 | static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) | ||
273 | { | ||
274 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
275 | u8 tll_ch_mask = 0; | ||
276 | unsigned reg = 0; | ||
277 | int ret = 0; | ||
278 | |||
279 | dev_dbg(omap->dev, "starting TI EHCI USB Controller\n"); | ||
280 | |||
281 | /* Enable Clocks for USBHOST */ | ||
282 | omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick"); | ||
283 | if (IS_ERR(omap->usbhost_ick)) { | ||
284 | ret = PTR_ERR(omap->usbhost_ick); | ||
285 | goto err_host_ick; | ||
286 | } | ||
287 | clk_enable(omap->usbhost_ick); | ||
288 | |||
289 | omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck"); | ||
290 | if (IS_ERR(omap->usbhost2_120m_fck)) { | ||
291 | ret = PTR_ERR(omap->usbhost2_120m_fck); | ||
292 | goto err_host_120m_fck; | ||
293 | } | ||
294 | clk_enable(omap->usbhost2_120m_fck); | ||
295 | |||
296 | omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck"); | ||
297 | if (IS_ERR(omap->usbhost1_48m_fck)) { | ||
298 | ret = PTR_ERR(omap->usbhost1_48m_fck); | ||
299 | goto err_host_48m_fck; | ||
300 | } | ||
301 | clk_enable(omap->usbhost1_48m_fck); | ||
302 | |||
303 | if (omap->phy_reset) { | ||
304 | /* Refer: ISSUE1 */ | ||
305 | if (gpio_is_valid(omap->reset_gpio_port[0])) { | ||
306 | gpio_request(omap->reset_gpio_port[0], | ||
307 | "USB1 PHY reset"); | ||
308 | gpio_direction_output(omap->reset_gpio_port[0], 0); | ||
309 | } | ||
310 | |||
311 | if (gpio_is_valid(omap->reset_gpio_port[1])) { | ||
312 | gpio_request(omap->reset_gpio_port[1], | ||
313 | "USB2 PHY reset"); | ||
314 | gpio_direction_output(omap->reset_gpio_port[1], 0); | ||
315 | } | ||
316 | |||
317 | /* Hold the PHY in RESET for enough time till DIR is high */ | ||
318 | udelay(10); | ||
319 | } | ||
320 | |||
321 | /* Configure TLL for 60Mhz clk for ULPI */ | ||
322 | omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck"); | ||
323 | if (IS_ERR(omap->usbtll_fck)) { | ||
324 | ret = PTR_ERR(omap->usbtll_fck); | ||
325 | goto err_tll_fck; | ||
326 | } | ||
327 | clk_enable(omap->usbtll_fck); | ||
328 | |||
329 | omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick"); | ||
330 | if (IS_ERR(omap->usbtll_ick)) { | ||
331 | ret = PTR_ERR(omap->usbtll_ick); | ||
332 | goto err_tll_ick; | ||
333 | } | ||
334 | clk_enable(omap->usbtll_ick); | ||
335 | |||
336 | /* perform TLL soft reset, and wait until reset is complete */ | ||
337 | ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
338 | OMAP_USBTLL_SYSCONFIG_SOFTRESET); | ||
339 | |||
340 | /* Wait for TLL reset to complete */ | ||
341 | while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
342 | & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { | ||
343 | cpu_relax(); | ||
344 | |||
345 | if (time_after(jiffies, timeout)) { | ||
346 | dev_dbg(omap->dev, "operation timed out\n"); | ||
347 | ret = -EINVAL; | ||
348 | goto err_sys_status; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | dev_dbg(omap->dev, "TLL RESET DONE\n"); | ||
353 | |||
354 | /* (1<<3) = no idle mode only for initial debugging */ | ||
355 | ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
356 | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | | ||
357 | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | | ||
358 | OMAP_USBTLL_SYSCONFIG_CACTIVITY); | ||
359 | |||
360 | |||
361 | /* Put UHH in NoIdle/NoStandby mode */ | ||
362 | reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); | ||
363 | reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | ||
364 | | OMAP_UHH_SYSCONFIG_SIDLEMODE | ||
365 | | OMAP_UHH_SYSCONFIG_CACTIVITY | ||
366 | | OMAP_UHH_SYSCONFIG_MIDLEMODE); | ||
367 | reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; | ||
368 | |||
369 | ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); | ||
370 | |||
371 | reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | ||
372 | |||
373 | /* setup ULPI bypass and burst configurations */ | ||
374 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | ||
375 | | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | ||
376 | | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); | ||
377 | reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; | ||
378 | |||
379 | if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) | ||
380 | reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; | ||
381 | if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) | ||
382 | reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; | ||
383 | if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) | ||
384 | reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; | ||
385 | |||
386 | /* Bypass the TLL module for PHY mode operation */ | ||
387 | if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { | ||
388 | dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n"); | ||
389 | if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || | ||
390 | (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || | ||
391 | (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) | ||
392 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
393 | else | ||
394 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
395 | } else { | ||
396 | dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); | ||
397 | if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) | ||
398 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
399 | else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) | ||
400 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
401 | |||
402 | if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) | ||
403 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
404 | else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) | ||
405 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
406 | |||
407 | if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY) | ||
408 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
409 | else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) | ||
410 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
411 | |||
412 | } | ||
413 | ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); | ||
414 | dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | ||
415 | |||
416 | |||
417 | /* | ||
418 | * An undocumented "feature" in the OMAP3 EHCI controller, | ||
419 | * causes suspended ports to be taken out of suspend when | ||
420 | * the USBCMD.Run/Stop bit is cleared (for example when | ||
421 | * we do ehci_bus_suspend). | ||
422 | * This breaks suspend-resume if the root-hub is allowed | ||
423 | * to suspend. Writing 1 to this undocumented register bit | ||
424 | * disables this feature and restores normal behavior. | ||
425 | */ | ||
426 | ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04, | ||
427 | EHCI_INSNREG04_DISABLE_UNSUSPEND); | ||
428 | |||
429 | if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || | ||
430 | (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || | ||
431 | (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { | ||
432 | |||
433 | if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) | ||
434 | tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; | ||
435 | if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) | ||
436 | tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; | ||
437 | if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) | ||
438 | tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; | ||
439 | |||
440 | /* Enable UTMI mode for required TLL channels */ | ||
441 | omap_usb_utmi_init(omap, tll_ch_mask); | ||
442 | } | ||
443 | |||
444 | if (omap->phy_reset) { | ||
445 | /* Refer ISSUE1: | ||
446 | * Hold the PHY in RESET for enough time till | ||
447 | * PHY is settled and ready | ||
448 | */ | ||
449 | udelay(10); | ||
450 | |||
451 | if (gpio_is_valid(omap->reset_gpio_port[0])) | ||
452 | gpio_set_value(omap->reset_gpio_port[0], 1); | ||
453 | |||
454 | if (gpio_is_valid(omap->reset_gpio_port[1])) | ||
455 | gpio_set_value(omap->reset_gpio_port[1], 1); | ||
456 | } | ||
457 | |||
458 | /* Soft reset the PHY using PHY reset command over ULPI */ | ||
459 | if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) | ||
460 | omap_ehci_soft_phy_reset(omap, 0); | ||
461 | if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) | ||
462 | omap_ehci_soft_phy_reset(omap, 1); | ||
463 | |||
464 | return 0; | ||
465 | |||
466 | err_sys_status: | ||
467 | clk_disable(omap->usbtll_ick); | ||
468 | clk_put(omap->usbtll_ick); | ||
469 | |||
470 | err_tll_ick: | ||
471 | clk_disable(omap->usbtll_fck); | ||
472 | clk_put(omap->usbtll_fck); | ||
473 | |||
474 | err_tll_fck: | ||
475 | clk_disable(omap->usbhost1_48m_fck); | ||
476 | clk_put(omap->usbhost1_48m_fck); | ||
477 | |||
478 | if (omap->phy_reset) { | ||
479 | if (gpio_is_valid(omap->reset_gpio_port[0])) | ||
480 | gpio_free(omap->reset_gpio_port[0]); | ||
481 | |||
482 | if (gpio_is_valid(omap->reset_gpio_port[1])) | ||
483 | gpio_free(omap->reset_gpio_port[1]); | ||
484 | } | ||
485 | |||
486 | err_host_48m_fck: | ||
487 | clk_disable(omap->usbhost2_120m_fck); | ||
488 | clk_put(omap->usbhost2_120m_fck); | ||
489 | |||
490 | err_host_120m_fck: | ||
491 | clk_disable(omap->usbhost_ick); | ||
492 | clk_put(omap->usbhost_ick); | ||
493 | |||
494 | err_host_ick: | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) | ||
499 | { | ||
500 | unsigned long timeout = jiffies + msecs_to_jiffies(100); | ||
501 | |||
502 | dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n"); | ||
503 | |||
504 | /* Reset OMAP modules for insmod/rmmod to work */ | ||
505 | ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, | ||
506 | OMAP_UHH_SYSCONFIG_SOFTRESET); | ||
507 | while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
508 | & (1 << 0))) { | ||
509 | cpu_relax(); | ||
510 | |||
511 | if (time_after(jiffies, timeout)) | ||
512 | dev_dbg(omap->dev, "operation timed out\n"); | ||
513 | } | ||
514 | |||
515 | while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
516 | & (1 << 1))) { | ||
517 | cpu_relax(); | ||
518 | |||
519 | if (time_after(jiffies, timeout)) | ||
520 | dev_dbg(omap->dev, "operation timed out\n"); | ||
521 | } | ||
522 | |||
523 | while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
524 | & (1 << 2))) { | ||
525 | cpu_relax(); | ||
526 | |||
527 | if (time_after(jiffies, timeout)) | ||
528 | dev_dbg(omap->dev, "operation timed out\n"); | ||
529 | } | ||
530 | |||
531 | ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); | ||
532 | |||
533 | while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
534 | & (1 << 0))) { | ||
535 | cpu_relax(); | ||
536 | |||
537 | if (time_after(jiffies, timeout)) | ||
538 | dev_dbg(omap->dev, "operation timed out\n"); | ||
539 | } | ||
540 | |||
541 | if (omap->usbtll_fck != NULL) { | ||
542 | clk_disable(omap->usbtll_fck); | ||
543 | clk_put(omap->usbtll_fck); | ||
544 | omap->usbtll_fck = NULL; | ||
545 | } | ||
546 | |||
547 | if (omap->usbhost_ick != NULL) { | ||
548 | clk_disable(omap->usbhost_ick); | ||
549 | clk_put(omap->usbhost_ick); | ||
550 | omap->usbhost_ick = NULL; | ||
551 | } | ||
552 | |||
553 | if (omap->usbhost1_48m_fck != NULL) { | ||
554 | clk_disable(omap->usbhost1_48m_fck); | ||
555 | clk_put(omap->usbhost1_48m_fck); | ||
556 | omap->usbhost1_48m_fck = NULL; | ||
557 | } | ||
558 | |||
559 | if (omap->usbhost2_120m_fck != NULL) { | ||
560 | clk_disable(omap->usbhost2_120m_fck); | ||
561 | clk_put(omap->usbhost2_120m_fck); | ||
562 | omap->usbhost2_120m_fck = NULL; | ||
563 | } | ||
564 | |||
565 | if (omap->usbtll_ick != NULL) { | ||
566 | clk_disable(omap->usbtll_ick); | ||
567 | clk_put(omap->usbtll_ick); | ||
568 | omap->usbtll_ick = NULL; | ||
569 | } | ||
570 | |||
571 | if (omap->phy_reset) { | ||
572 | if (gpio_is_valid(omap->reset_gpio_port[0])) | ||
573 | gpio_free(omap->reset_gpio_port[0]); | ||
574 | |||
575 | if (gpio_is_valid(omap->reset_gpio_port[1])) | ||
576 | gpio_free(omap->reset_gpio_port[1]); | ||
577 | } | ||
578 | |||
579 | dev_dbg(omap->dev, "Clock to USB host has been disabled\n"); | ||
580 | } | ||
581 | |||
582 | /*-------------------------------------------------------------------------*/ | ||
583 | |||
584 | static const struct hc_driver ehci_omap_hc_driver; | ||
585 | 101 | ||
586 | /* configure so an HC device and id are always provided */ | 102 | /* configure so an HC device and id are always provided */ |
587 | /* always called with process context; sleeping is OK */ | 103 | /* always called with process context; sleeping is OK */ |
@@ -595,155 +111,132 @@ static const struct hc_driver ehci_omap_hc_driver; | |||
595 | */ | 111 | */ |
596 | static int ehci_hcd_omap_probe(struct platform_device *pdev) | 112 | static int ehci_hcd_omap_probe(struct platform_device *pdev) |
597 | { | 113 | { |
598 | struct ehci_hcd_omap_platform_data *pdata = pdev->dev.platform_data; | 114 | struct device *dev = &pdev->dev; |
599 | struct ehci_hcd_omap *omap; | 115 | struct ehci_hcd_omap_platform_data *pdata = dev->platform_data; |
600 | struct resource *res; | 116 | struct resource *res; |
601 | struct usb_hcd *hcd; | 117 | struct usb_hcd *hcd; |
602 | 118 | void __iomem *regs; | |
603 | int irq = platform_get_irq(pdev, 0); | 119 | struct ehci_hcd *omap_ehci; |
604 | int ret = -ENODEV; | 120 | int ret = -ENODEV; |
605 | int i; | 121 | int irq; |
606 | char supply[7]; | 122 | int i; |
607 | 123 | char supply[7]; | |
608 | if (!pdata) { | ||
609 | dev_dbg(&pdev->dev, "missing platform_data\n"); | ||
610 | goto err_pdata; | ||
611 | } | ||
612 | 124 | ||
613 | if (usb_disabled()) | 125 | if (usb_disabled()) |
614 | goto err_disabled; | 126 | return -ENODEV; |
615 | 127 | ||
616 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); | 128 | if (!dev->parent) { |
617 | if (!omap) { | 129 | dev_err(dev, "Missing parent device\n"); |
618 | ret = -ENOMEM; | 130 | return -ENODEV; |
619 | goto err_disabled; | ||
620 | } | 131 | } |
621 | 132 | ||
622 | hcd = usb_create_hcd(&ehci_omap_hc_driver, &pdev->dev, | 133 | irq = platform_get_irq_byname(pdev, "ehci-irq"); |
623 | dev_name(&pdev->dev)); | 134 | if (irq < 0) { |
624 | if (!hcd) { | 135 | dev_err(dev, "EHCI irq failed\n"); |
625 | dev_dbg(&pdev->dev, "failed to create hcd with err %d\n", ret); | 136 | return -ENODEV; |
626 | ret = -ENOMEM; | ||
627 | goto err_create_hcd; | ||
628 | } | 137 | } |
629 | 138 | ||
630 | platform_set_drvdata(pdev, omap); | 139 | res = platform_get_resource_byname(pdev, |
631 | omap->dev = &pdev->dev; | 140 | IORESOURCE_MEM, "ehci"); |
632 | omap->phy_reset = pdata->phy_reset; | 141 | if (!res) { |
633 | omap->reset_gpio_port[0] = pdata->reset_gpio_port[0]; | 142 | dev_err(dev, "UHH EHCI get resource failed\n"); |
634 | omap->reset_gpio_port[1] = pdata->reset_gpio_port[1]; | 143 | return -ENODEV; |
635 | omap->reset_gpio_port[2] = pdata->reset_gpio_port[2]; | ||
636 | omap->port_mode[0] = pdata->port_mode[0]; | ||
637 | omap->port_mode[1] = pdata->port_mode[1]; | ||
638 | omap->port_mode[2] = pdata->port_mode[2]; | ||
639 | omap->ehci = hcd_to_ehci(hcd); | ||
640 | omap->ehci->sbrn = 0x20; | ||
641 | |||
642 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
643 | |||
644 | hcd->rsrc_start = res->start; | ||
645 | hcd->rsrc_len = resource_size(res); | ||
646 | |||
647 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
648 | if (!hcd->regs) { | ||
649 | dev_err(&pdev->dev, "EHCI ioremap failed\n"); | ||
650 | ret = -ENOMEM; | ||
651 | goto err_ioremap; | ||
652 | } | 144 | } |
653 | 145 | ||
654 | /* we know this is the memory we want, no need to ioremap again */ | 146 | regs = ioremap(res->start, resource_size(res)); |
655 | omap->ehci->caps = hcd->regs; | 147 | if (!regs) { |
656 | omap->ehci_base = hcd->regs; | 148 | dev_err(dev, "UHH EHCI ioremap failed\n"); |
657 | 149 | return -ENOMEM; | |
658 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
659 | omap->uhh_base = ioremap(res->start, resource_size(res)); | ||
660 | if (!omap->uhh_base) { | ||
661 | dev_err(&pdev->dev, "UHH ioremap failed\n"); | ||
662 | ret = -ENOMEM; | ||
663 | goto err_uhh_ioremap; | ||
664 | } | 150 | } |
665 | 151 | ||
666 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | 152 | hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, |
667 | omap->tll_base = ioremap(res->start, resource_size(res)); | 153 | dev_name(dev)); |
668 | if (!omap->tll_base) { | 154 | if (!hcd) { |
669 | dev_err(&pdev->dev, "TLL ioremap failed\n"); | 155 | dev_err(dev, "failed to create hcd with err %d\n", ret); |
670 | ret = -ENOMEM; | 156 | ret = -ENOMEM; |
671 | goto err_tll_ioremap; | 157 | goto err_io; |
672 | } | 158 | } |
673 | 159 | ||
160 | hcd->rsrc_start = res->start; | ||
161 | hcd->rsrc_len = resource_size(res); | ||
162 | hcd->regs = regs; | ||
163 | |||
674 | /* get ehci regulator and enable */ | 164 | /* get ehci regulator and enable */ |
675 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { | 165 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { |
676 | if (omap->port_mode[i] != EHCI_HCD_OMAP_MODE_PHY) { | 166 | if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { |
677 | omap->regulator[i] = NULL; | 167 | pdata->regulator[i] = NULL; |
678 | continue; | 168 | continue; |
679 | } | 169 | } |
680 | snprintf(supply, sizeof(supply), "hsusb%d", i); | 170 | snprintf(supply, sizeof(supply), "hsusb%d", i); |
681 | omap->regulator[i] = regulator_get(omap->dev, supply); | 171 | pdata->regulator[i] = regulator_get(dev, supply); |
682 | if (IS_ERR(omap->regulator[i])) { | 172 | if (IS_ERR(pdata->regulator[i])) { |
683 | omap->regulator[i] = NULL; | 173 | pdata->regulator[i] = NULL; |
684 | dev_dbg(&pdev->dev, | 174 | dev_dbg(dev, |
685 | "failed to get ehci port%d regulator\n", i); | 175 | "failed to get ehci port%d regulator\n", i); |
686 | } else { | 176 | } else { |
687 | regulator_enable(omap->regulator[i]); | 177 | regulator_enable(pdata->regulator[i]); |
688 | } | 178 | } |
689 | } | 179 | } |
690 | 180 | ||
691 | ret = omap_start_ehc(omap, hcd); | 181 | ret = omap_usbhs_enable(dev); |
692 | if (ret) { | 182 | if (ret) { |
693 | dev_dbg(&pdev->dev, "failed to start ehci\n"); | 183 | dev_err(dev, "failed to start usbhs with err %d\n", ret); |
694 | goto err_start; | 184 | goto err_enable; |
695 | } | 185 | } |
696 | 186 | ||
697 | omap->ehci->regs = hcd->regs | 187 | /* |
698 | + HC_LENGTH(readl(&omap->ehci->caps->hc_capbase)); | 188 | * An undocumented "feature" in the OMAP3 EHCI controller, |
189 | * causes suspended ports to be taken out of suspend when | ||
190 | * the USBCMD.Run/Stop bit is cleared (for example when | ||
191 | * we do ehci_bus_suspend). | ||
192 | * This breaks suspend-resume if the root-hub is allowed | ||
193 | * to suspend. Writing 1 to this undocumented register bit | ||
194 | * disables this feature and restores normal behavior. | ||
195 | */ | ||
196 | ehci_write(regs, EHCI_INSNREG04, | ||
197 | EHCI_INSNREG04_DISABLE_UNSUSPEND); | ||
198 | |||
199 | /* Soft reset the PHY using PHY reset command over ULPI */ | ||
200 | if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) | ||
201 | omap_ehci_soft_phy_reset(pdev, 0); | ||
202 | if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) | ||
203 | omap_ehci_soft_phy_reset(pdev, 1); | ||
204 | |||
205 | omap_ehci = hcd_to_ehci(hcd); | ||
206 | omap_ehci->sbrn = 0x20; | ||
699 | 207 | ||
700 | dbg_hcs_params(omap->ehci, "reset"); | 208 | /* we know this is the memory we want, no need to ioremap again */ |
701 | dbg_hcc_params(omap->ehci, "reset"); | 209 | omap_ehci->caps = hcd->regs; |
210 | omap_ehci->regs = hcd->regs | ||
211 | + HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase)); | ||
212 | |||
213 | dbg_hcs_params(omap_ehci, "reset"); | ||
214 | dbg_hcc_params(omap_ehci, "reset"); | ||
702 | 215 | ||
703 | /* cache this readonly data; minimize chip reads */ | 216 | /* cache this readonly data; minimize chip reads */ |
704 | omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params); | 217 | omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params); |
705 | 218 | ||
706 | ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); | 219 | ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); |
707 | if (ret) { | 220 | if (ret) { |
708 | dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); | 221 | dev_err(dev, "failed to add hcd with err %d\n", ret); |
709 | goto err_add_hcd; | 222 | goto err_add_hcd; |
710 | } | 223 | } |
711 | 224 | ||
712 | /* root ports should always stay powered */ | 225 | /* root ports should always stay powered */ |
713 | ehci_port_power(omap->ehci, 1); | 226 | ehci_port_power(omap_ehci, 1); |
714 | 227 | ||
715 | return 0; | 228 | return 0; |
716 | 229 | ||
717 | err_add_hcd: | 230 | err_add_hcd: |
718 | omap_stop_ehc(omap, hcd); | 231 | omap_usbhs_disable(dev); |
719 | |||
720 | err_start: | ||
721 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { | ||
722 | if (omap->regulator[i]) { | ||
723 | regulator_disable(omap->regulator[i]); | ||
724 | regulator_put(omap->regulator[i]); | ||
725 | } | ||
726 | } | ||
727 | iounmap(omap->tll_base); | ||
728 | |||
729 | err_tll_ioremap: | ||
730 | iounmap(omap->uhh_base); | ||
731 | 232 | ||
732 | err_uhh_ioremap: | 233 | err_enable: |
733 | iounmap(hcd->regs); | ||
734 | |||
735 | err_ioremap: | ||
736 | usb_put_hcd(hcd); | 234 | usb_put_hcd(hcd); |
737 | 235 | ||
738 | err_create_hcd: | 236 | err_io: |
739 | kfree(omap); | ||
740 | err_disabled: | ||
741 | err_pdata: | ||
742 | return ret; | 237 | return ret; |
743 | } | 238 | } |
744 | 239 | ||
745 | /* may be called without controller electrically present */ | ||
746 | /* may be called with controller, bus, and devices active */ | ||
747 | 240 | ||
748 | /** | 241 | /** |
749 | * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs | 242 | * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs |
@@ -755,31 +248,18 @@ err_pdata: | |||
755 | */ | 248 | */ |
756 | static int ehci_hcd_omap_remove(struct platform_device *pdev) | 249 | static int ehci_hcd_omap_remove(struct platform_device *pdev) |
757 | { | 250 | { |
758 | struct ehci_hcd_omap *omap = platform_get_drvdata(pdev); | 251 | struct device *dev = &pdev->dev; |
759 | struct usb_hcd *hcd = ehci_to_hcd(omap->ehci); | 252 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
760 | int i; | ||
761 | 253 | ||
762 | usb_remove_hcd(hcd); | 254 | usb_remove_hcd(hcd); |
763 | omap_stop_ehc(omap, hcd); | 255 | omap_usbhs_disable(dev); |
764 | iounmap(hcd->regs); | ||
765 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { | ||
766 | if (omap->regulator[i]) { | ||
767 | regulator_disable(omap->regulator[i]); | ||
768 | regulator_put(omap->regulator[i]); | ||
769 | } | ||
770 | } | ||
771 | iounmap(omap->tll_base); | ||
772 | iounmap(omap->uhh_base); | ||
773 | usb_put_hcd(hcd); | 256 | usb_put_hcd(hcd); |
774 | kfree(omap); | ||
775 | |||
776 | return 0; | 257 | return 0; |
777 | } | 258 | } |
778 | 259 | ||
779 | static void ehci_hcd_omap_shutdown(struct platform_device *pdev) | 260 | static void ehci_hcd_omap_shutdown(struct platform_device *pdev) |
780 | { | 261 | { |
781 | struct ehci_hcd_omap *omap = platform_get_drvdata(pdev); | 262 | struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); |
782 | struct usb_hcd *hcd = ehci_to_hcd(omap->ehci); | ||
783 | 263 | ||
784 | if (hcd->driver->shutdown) | 264 | if (hcd->driver->shutdown) |
785 | hcd->driver->shutdown(hcd); | 265 | hcd->driver->shutdown(hcd); |