diff options
author | Keshava Munegowda <keshava_mgowda@ti.com> | 2011-03-01 09:38:21 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-03-01 10:02:49 -0500 |
commit | 19403165c272cc4ed00c97973e7271714b009708 (patch) | |
tree | 9f0923ec4d4514b9a9d615d5ca8d3d0bb0e881ce /drivers/usb/host/ehci-omap.c | |
parent | 3b68ae73d8afa925807ebaae7eb14e2afd43f5b5 (diff) |
usb: host: omap: ehci and ohci simplification
The ehci and ohci drivers are simplified; Since
UHH and TLL initialization, clock handling are
done by common usbhs core driver, these functionalities
are removed from ehci and ohci drivers.
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/host/ehci-omap.c')
-rw-r--r-- | drivers/usb/host/ehci-omap.c | 1016 |
1 files changed, 84 insertions, 932 deletions
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 18df6c6a5803..7e41a95c5ceb 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c | |||
@@ -4,9 +4,10 @@ | |||
4 | * Bus Glue for the EHCI controllers in OMAP3/4 | 4 | * Bus Glue for the EHCI controllers in OMAP3/4 |
5 | * Tested on several OMAP3 boards, and OMAP4 Pandaboard | 5 | * Tested on several OMAP3 boards, and OMAP4 Pandaboard |
6 | * | 6 | * |
7 | * Copyright (C) 2007-2010 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> | 9 | * Author: Anand Gadiyar <gadiyar@ti.com> |
10 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | ||
10 | * | 11 | * |
11 | * Copyright (C) 2009 Nokia Corporation | 12 | * Copyright (C) 2009 Nokia Corporation |
12 | * Contact: Felipe Balbi <felipe.balbi@nokia.com> | 13 | * Contact: Felipe Balbi <felipe.balbi@nokia.com> |
@@ -27,116 +28,19 @@ | |||
27 | * along with this program; if not, write to the Free Software | 28 | * along with this program; if not, write to the Free Software |
28 | * 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 |
29 | * | 30 | * |
30 | * TODO (last updated Nov 21, 2010): | 31 | * TODO (last updated Feb 27, 2010): |
31 | * - add kernel-doc | 32 | * - add kernel-doc |
32 | * - enable AUTOIDLE | 33 | * - enable AUTOIDLE |
33 | * - add suspend/resume | 34 | * - add suspend/resume |
34 | * - move workarounds to board-files | ||
35 | * - factor out code common to OHCI | ||
36 | * - add HSIC and TLL support | 35 | * - add HSIC and TLL support |
37 | * - convert to use hwmod and runtime PM | 36 | * - convert to use hwmod and runtime PM |
38 | */ | 37 | */ |
39 | 38 | ||
40 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
41 | #include <linux/clk.h> | ||
42 | #include <linux/gpio.h> | ||
43 | #include <linux/regulator/consumer.h> | ||
44 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
45 | #include <linux/usb/ulpi.h> | 41 | #include <linux/usb/ulpi.h> |
46 | #include <plat/usb.h> | 42 | #include <plat/usb.h> |
47 | 43 | ||
48 | /* | ||
49 | * OMAP USBHOST Register addresses: VIRTUAL ADDRESSES | ||
50 | * Use ehci_omap_readl()/ehci_omap_writel() functions | ||
51 | */ | ||
52 | |||
53 | /* TLL Register Set */ | ||
54 | #define OMAP_USBTLL_REVISION (0x00) | ||
55 | #define OMAP_USBTLL_SYSCONFIG (0x10) | ||
56 | #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) | ||
57 | #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) | ||
58 | #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
59 | #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) | ||
60 | #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) | ||
61 | |||
62 | #define OMAP_USBTLL_SYSSTATUS (0x14) | ||
63 | #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) | ||
64 | |||
65 | #define OMAP_USBTLL_IRQSTATUS (0x18) | ||
66 | #define OMAP_USBTLL_IRQENABLE (0x1C) | ||
67 | |||
68 | #define OMAP_TLL_SHARED_CONF (0x30) | ||
69 | #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) | ||
70 | #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) | ||
71 | #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) | ||
72 | #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) | ||
73 | #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) | ||
74 | |||
75 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | ||
76 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | ||
77 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | ||
78 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | ||
79 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | ||
80 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | ||
81 | |||
82 | #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) | ||
83 | #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) | ||
84 | #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) | ||
85 | #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) | ||
86 | #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) | ||
87 | #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) | ||
88 | #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) | ||
89 | #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) | ||
90 | #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) | ||
91 | |||
92 | #define OMAP_TLL_CHANNEL_COUNT 3 | ||
93 | #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) | ||
94 | #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) | ||
95 | #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) | ||
96 | |||
97 | /* UHH Register Set */ | ||
98 | #define OMAP_UHH_REVISION (0x00) | ||
99 | #define OMAP_UHH_SYSCONFIG (0x10) | ||
100 | #define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12) | ||
101 | #define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8) | ||
102 | #define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3) | ||
103 | #define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
104 | #define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1) | ||
105 | #define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0) | ||
106 | |||
107 | #define OMAP_UHH_SYSSTATUS (0x14) | ||
108 | #define OMAP_UHH_HOSTCONFIG (0x40) | ||
109 | #define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0) | ||
110 | #define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0) | ||
111 | #define OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS (1 << 11) | ||
112 | #define OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS (1 << 12) | ||
113 | #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2) | ||
114 | #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3) | ||
115 | #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4) | ||
116 | #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5) | ||
117 | #define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS (1 << 8) | ||
118 | #define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9) | ||
119 | #define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10) | ||
120 | |||
121 | /* OMAP4-specific defines */ | ||
122 | #define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2) | ||
123 | #define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2) | ||
124 | |||
125 | #define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4) | ||
126 | #define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4) | ||
127 | #define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0) | ||
128 | |||
129 | #define OMAP4_P1_MODE_CLEAR (3 << 16) | ||
130 | #define OMAP4_P1_MODE_TLL (1 << 16) | ||
131 | #define OMAP4_P1_MODE_HSIC (3 << 16) | ||
132 | #define OMAP4_P2_MODE_CLEAR (3 << 18) | ||
133 | #define OMAP4_P2_MODE_TLL (1 << 18) | ||
134 | #define OMAP4_P2_MODE_HSIC (3 << 18) | ||
135 | |||
136 | #define OMAP_REV2_TLL_CHANNEL_COUNT 2 | ||
137 | |||
138 | #define OMAP_UHH_DEBUG_CSR (0x44) | ||
139 | |||
140 | /* EHCI Register Set */ | 44 | /* EHCI Register Set */ |
141 | #define EHCI_INSNREG04 (0xA0) | 45 | #define EHCI_INSNREG04 (0xA0) |
142 | #define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5) | 46 | #define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5) |
@@ -148,141 +52,24 @@ | |||
148 | #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 | 52 | #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 |
149 | #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 | 53 | #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 |
150 | 54 | ||
151 | /* Values of UHH_REVISION - Note: these are not given in the TRM */ | 55 | /*-------------------------------------------------------------------------*/ |
152 | #define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */ | ||
153 | #define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */ | ||
154 | 56 | ||
155 | #define is_omap_ehci_rev1(x) (x->omap_ehci_rev == OMAP_EHCI_REV1) | 57 | static const struct hc_driver ehci_omap_hc_driver; |
156 | #define is_omap_ehci_rev2(x) (x->omap_ehci_rev == OMAP_EHCI_REV2) | ||
157 | 58 | ||
158 | #define is_ehci_phy_mode(x) (x == OMAP_EHCI_PORT_MODE_PHY) | ||
159 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) | ||
160 | #define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC) | ||
161 | 59 | ||
162 | /*-------------------------------------------------------------------------*/ | 60 | static inline void ehci_write(void __iomem *base, u32 reg, u32 val) |
163 | |||
164 | static inline void ehci_omap_writel(void __iomem *base, u32 reg, u32 val) | ||
165 | { | 61 | { |
166 | __raw_writel(val, base + reg); | 62 | __raw_writel(val, base + reg); |
167 | } | 63 | } |
168 | 64 | ||
169 | static inline u32 ehci_omap_readl(void __iomem *base, u32 reg) | 65 | static inline u32 ehci_read(void __iomem *base, u32 reg) |
170 | { | 66 | { |
171 | return __raw_readl(base + reg); | 67 | return __raw_readl(base + reg); |
172 | } | 68 | } |
173 | 69 | ||
174 | static inline void ehci_omap_writeb(void __iomem *base, u8 reg, u8 val) | 70 | static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port) |
175 | { | ||
176 | __raw_writeb(val, base + reg); | ||
177 | } | ||
178 | |||
179 | static inline u8 ehci_omap_readb(void __iomem *base, u8 reg) | ||
180 | { | ||
181 | return __raw_readb(base + reg); | ||
182 | } | ||
183 | |||
184 | /*-------------------------------------------------------------------------*/ | ||
185 | |||
186 | struct ehci_hcd_omap { | ||
187 | struct ehci_hcd *ehci; | ||
188 | struct device *dev; | ||
189 | |||
190 | struct clk *usbhost_ick; | ||
191 | struct clk *usbhost_hs_fck; | ||
192 | struct clk *usbhost_fs_fck; | ||
193 | struct clk *usbtll_fck; | ||
194 | struct clk *usbtll_ick; | ||
195 | struct clk *xclk60mhsp1_ck; | ||
196 | struct clk *xclk60mhsp2_ck; | ||
197 | struct clk *utmi_p1_fck; | ||
198 | struct clk *usbhost_p1_fck; | ||
199 | struct clk *usbtll_p1_fck; | ||
200 | struct clk *utmi_p2_fck; | ||
201 | struct clk *usbhost_p2_fck; | ||
202 | struct clk *usbtll_p2_fck; | ||
203 | |||
204 | /* FIXME the following two workarounds are | ||
205 | * board specific not silicon-specific so these | ||
206 | * should be moved to board-file instead. | ||
207 | * | ||
208 | * Maybe someone from TI will know better which | ||
209 | * board is affected and needs the workarounds | ||
210 | * to be applied | ||
211 | */ | ||
212 | |||
213 | /* gpio for resetting phy */ | ||
214 | int reset_gpio_port[OMAP3_HS_USB_PORTS]; | ||
215 | |||
216 | /* phy reset workaround */ | ||
217 | int phy_reset; | ||
218 | |||
219 | /* IP revision */ | ||
220 | u32 omap_ehci_rev; | ||
221 | |||
222 | /* desired phy_mode: TLL, PHY */ | ||
223 | enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; | ||
224 | |||
225 | void __iomem *uhh_base; | ||
226 | void __iomem *tll_base; | ||
227 | void __iomem *ehci_base; | ||
228 | |||
229 | /* Regulators for USB PHYs. | ||
230 | * Each PHY can have a separate regulator. | ||
231 | */ | ||
232 | struct regulator *regulator[OMAP3_HS_USB_PORTS]; | ||
233 | }; | ||
234 | |||
235 | /*-------------------------------------------------------------------------*/ | ||
236 | |||
237 | static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask, | ||
238 | u8 tll_channel_count) | ||
239 | { | ||
240 | unsigned reg; | ||
241 | int i; | ||
242 | |||
243 | /* Program the 3 TLL channels upfront */ | ||
244 | for (i = 0; i < tll_channel_count; i++) { | ||
245 | reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); | ||
246 | |||
247 | /* Disable AutoIdle, BitStuffing and use SDR Mode */ | ||
248 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | ||
249 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | ||
250 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | ||
251 | ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); | ||
252 | } | ||
253 | |||
254 | /* Program Common TLL register */ | ||
255 | reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF); | ||
256 | reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | ||
257 | | OMAP_TLL_SHARED_CONF_USB_DIVRATION | ||
258 | | OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN); | ||
259 | reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; | ||
260 | |||
261 | ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); | ||
262 | |||
263 | /* Enable channels now */ | ||
264 | for (i = 0; i < tll_channel_count; i++) { | ||
265 | reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); | ||
266 | |||
267 | /* Enable only the reg that is needed */ | ||
268 | if (!(tll_channel_mask & 1<<i)) | ||
269 | continue; | ||
270 | |||
271 | reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; | ||
272 | ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); | ||
273 | |||
274 | ehci_omap_writeb(omap->tll_base, | ||
275 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); | ||
276 | dev_dbg(omap->dev, "ULPI_SCRATCH_REG[ch=%d]= 0x%02x\n", | ||
277 | i+1, ehci_omap_readb(omap->tll_base, | ||
278 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i))); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /*-------------------------------------------------------------------------*/ | ||
283 | |||
284 | static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port) | ||
285 | { | 71 | { |
72 | struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); | ||
286 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | 73 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); |
287 | unsigned reg = 0; | 74 | unsigned reg = 0; |
288 | 75 | ||
@@ -296,600 +83,20 @@ static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port) | |||
296 | /* start ULPI access*/ | 83 | /* start ULPI access*/ |
297 | | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); | 84 | | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); |
298 | 85 | ||
299 | ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI, reg); | 86 | ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg); |
300 | 87 | ||
301 | /* Wait for ULPI access completion */ | 88 | /* Wait for ULPI access completion */ |
302 | while ((ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI) | 89 | while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI) |
303 | & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { | 90 | & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { |
304 | cpu_relax(); | 91 | cpu_relax(); |
305 | 92 | ||
306 | if (time_after(jiffies, timeout)) { | 93 | if (time_after(jiffies, timeout)) { |
307 | dev_dbg(omap->dev, "phy reset operation timed out\n"); | 94 | dev_dbg(&pdev->dev, "phy reset operation timed out\n"); |
308 | break; | 95 | break; |
309 | } | 96 | } |
310 | } | 97 | } |
311 | } | 98 | } |
312 | 99 | ||
313 | /* omap_start_ehc | ||
314 | * - Start the TI USBHOST controller | ||
315 | */ | ||
316 | static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) | ||
317 | { | ||
318 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
319 | u8 tll_ch_mask = 0; | ||
320 | unsigned reg = 0; | ||
321 | int ret = 0; | ||
322 | |||
323 | dev_dbg(omap->dev, "starting TI EHCI USB Controller\n"); | ||
324 | |||
325 | /* Enable Clocks for USBHOST */ | ||
326 | omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick"); | ||
327 | if (IS_ERR(omap->usbhost_ick)) { | ||
328 | ret = PTR_ERR(omap->usbhost_ick); | ||
329 | goto err_host_ick; | ||
330 | } | ||
331 | clk_enable(omap->usbhost_ick); | ||
332 | |||
333 | omap->usbhost_hs_fck = clk_get(omap->dev, "hs_fck"); | ||
334 | if (IS_ERR(omap->usbhost_hs_fck)) { | ||
335 | ret = PTR_ERR(omap->usbhost_hs_fck); | ||
336 | goto err_host_120m_fck; | ||
337 | } | ||
338 | clk_enable(omap->usbhost_hs_fck); | ||
339 | |||
340 | omap->usbhost_fs_fck = clk_get(omap->dev, "fs_fck"); | ||
341 | if (IS_ERR(omap->usbhost_fs_fck)) { | ||
342 | ret = PTR_ERR(omap->usbhost_fs_fck); | ||
343 | goto err_host_48m_fck; | ||
344 | } | ||
345 | clk_enable(omap->usbhost_fs_fck); | ||
346 | |||
347 | if (omap->phy_reset) { | ||
348 | /* Refer: ISSUE1 */ | ||
349 | if (gpio_is_valid(omap->reset_gpio_port[0])) { | ||
350 | gpio_request(omap->reset_gpio_port[0], | ||
351 | "USB1 PHY reset"); | ||
352 | gpio_direction_output(omap->reset_gpio_port[0], 0); | ||
353 | } | ||
354 | |||
355 | if (gpio_is_valid(omap->reset_gpio_port[1])) { | ||
356 | gpio_request(omap->reset_gpio_port[1], | ||
357 | "USB2 PHY reset"); | ||
358 | gpio_direction_output(omap->reset_gpio_port[1], 0); | ||
359 | } | ||
360 | |||
361 | /* Hold the PHY in RESET for enough time till DIR is high */ | ||
362 | udelay(10); | ||
363 | } | ||
364 | |||
365 | /* Configure TLL for 60Mhz clk for ULPI */ | ||
366 | omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck"); | ||
367 | if (IS_ERR(omap->usbtll_fck)) { | ||
368 | ret = PTR_ERR(omap->usbtll_fck); | ||
369 | goto err_tll_fck; | ||
370 | } | ||
371 | clk_enable(omap->usbtll_fck); | ||
372 | |||
373 | omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick"); | ||
374 | if (IS_ERR(omap->usbtll_ick)) { | ||
375 | ret = PTR_ERR(omap->usbtll_ick); | ||
376 | goto err_tll_ick; | ||
377 | } | ||
378 | clk_enable(omap->usbtll_ick); | ||
379 | |||
380 | omap->omap_ehci_rev = ehci_omap_readl(omap->uhh_base, | ||
381 | OMAP_UHH_REVISION); | ||
382 | dev_dbg(omap->dev, "OMAP UHH_REVISION 0x%x\n", | ||
383 | omap->omap_ehci_rev); | ||
384 | |||
385 | /* | ||
386 | * Enable per-port clocks as needed (newer controllers only). | ||
387 | * - External ULPI clock for PHY mode | ||
388 | * - Internal clocks for TLL and HSIC modes (TODO) | ||
389 | */ | ||
390 | if (is_omap_ehci_rev2(omap)) { | ||
391 | switch (omap->port_mode[0]) { | ||
392 | case OMAP_EHCI_PORT_MODE_PHY: | ||
393 | omap->xclk60mhsp1_ck = clk_get(omap->dev, | ||
394 | "xclk60mhsp1_ck"); | ||
395 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | ||
396 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | ||
397 | dev_err(omap->dev, | ||
398 | "Unable to get Port1 ULPI clock\n"); | ||
399 | } | ||
400 | |||
401 | omap->utmi_p1_fck = clk_get(omap->dev, | ||
402 | "utmi_p1_gfclk"); | ||
403 | if (IS_ERR(omap->utmi_p1_fck)) { | ||
404 | ret = PTR_ERR(omap->utmi_p1_fck); | ||
405 | dev_err(omap->dev, | ||
406 | "Unable to get utmi_p1_fck\n"); | ||
407 | } | ||
408 | |||
409 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
410 | omap->xclk60mhsp1_ck); | ||
411 | if (ret != 0) { | ||
412 | dev_err(omap->dev, | ||
413 | "Unable to set P1 f-clock\n"); | ||
414 | } | ||
415 | break; | ||
416 | case OMAP_EHCI_PORT_MODE_TLL: | ||
417 | omap->xclk60mhsp1_ck = clk_get(omap->dev, | ||
418 | "init_60m_fclk"); | ||
419 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | ||
420 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | ||
421 | dev_err(omap->dev, | ||
422 | "Unable to get Port1 ULPI clock\n"); | ||
423 | } | ||
424 | |||
425 | omap->utmi_p1_fck = clk_get(omap->dev, | ||
426 | "utmi_p1_gfclk"); | ||
427 | if (IS_ERR(omap->utmi_p1_fck)) { | ||
428 | ret = PTR_ERR(omap->utmi_p1_fck); | ||
429 | dev_err(omap->dev, | ||
430 | "Unable to get utmi_p1_fck\n"); | ||
431 | } | ||
432 | |||
433 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
434 | omap->xclk60mhsp1_ck); | ||
435 | if (ret != 0) { | ||
436 | dev_err(omap->dev, | ||
437 | "Unable to set P1 f-clock\n"); | ||
438 | } | ||
439 | |||
440 | omap->usbhost_p1_fck = clk_get(omap->dev, | ||
441 | "usb_host_hs_utmi_p1_clk"); | ||
442 | if (IS_ERR(omap->usbhost_p1_fck)) { | ||
443 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
444 | dev_err(omap->dev, | ||
445 | "Unable to get HOST PORT 1 clk\n"); | ||
446 | } else { | ||
447 | clk_enable(omap->usbhost_p1_fck); | ||
448 | } | ||
449 | |||
450 | omap->usbtll_p1_fck = clk_get(omap->dev, | ||
451 | "usb_tll_hs_usb_ch0_clk"); | ||
452 | |||
453 | if (IS_ERR(omap->usbtll_p1_fck)) { | ||
454 | ret = PTR_ERR(omap->usbtll_p1_fck); | ||
455 | dev_err(omap->dev, | ||
456 | "Unable to get TLL CH0 clk\n"); | ||
457 | } else { | ||
458 | clk_enable(omap->usbtll_p1_fck); | ||
459 | } | ||
460 | break; | ||
461 | /* TODO */ | ||
462 | default: | ||
463 | break; | ||
464 | } | ||
465 | switch (omap->port_mode[1]) { | ||
466 | case OMAP_EHCI_PORT_MODE_PHY: | ||
467 | omap->xclk60mhsp2_ck = clk_get(omap->dev, | ||
468 | "xclk60mhsp2_ck"); | ||
469 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | ||
470 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | ||
471 | dev_err(omap->dev, | ||
472 | "Unable to get Port2 ULPI clock\n"); | ||
473 | } | ||
474 | |||
475 | omap->utmi_p2_fck = clk_get(omap->dev, | ||
476 | "utmi_p2_gfclk"); | ||
477 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
478 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
479 | dev_err(omap->dev, | ||
480 | "Unable to get utmi_p2_fck\n"); | ||
481 | } | ||
482 | |||
483 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
484 | omap->xclk60mhsp2_ck); | ||
485 | if (ret != 0) { | ||
486 | dev_err(omap->dev, | ||
487 | "Unable to set P2 f-clock\n"); | ||
488 | } | ||
489 | break; | ||
490 | case OMAP_EHCI_PORT_MODE_TLL: | ||
491 | omap->xclk60mhsp2_ck = clk_get(omap->dev, | ||
492 | "init_60m_fclk"); | ||
493 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | ||
494 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | ||
495 | dev_err(omap->dev, | ||
496 | "Unable to get Port2 ULPI clock\n"); | ||
497 | } | ||
498 | |||
499 | omap->utmi_p2_fck = clk_get(omap->dev, | ||
500 | "utmi_p2_gfclk"); | ||
501 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
502 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
503 | dev_err(omap->dev, | ||
504 | "Unable to get utmi_p2_fck\n"); | ||
505 | } | ||
506 | |||
507 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
508 | omap->xclk60mhsp2_ck); | ||
509 | if (ret != 0) { | ||
510 | dev_err(omap->dev, | ||
511 | "Unable to set P2 f-clock\n"); | ||
512 | } | ||
513 | |||
514 | omap->usbhost_p2_fck = clk_get(omap->dev, | ||
515 | "usb_host_hs_utmi_p2_clk"); | ||
516 | if (IS_ERR(omap->usbhost_p2_fck)) { | ||
517 | ret = PTR_ERR(omap->usbhost_p2_fck); | ||
518 | dev_err(omap->dev, | ||
519 | "Unable to get HOST PORT 2 clk\n"); | ||
520 | } else { | ||
521 | clk_enable(omap->usbhost_p2_fck); | ||
522 | } | ||
523 | |||
524 | omap->usbtll_p2_fck = clk_get(omap->dev, | ||
525 | "usb_tll_hs_usb_ch1_clk"); | ||
526 | |||
527 | if (IS_ERR(omap->usbtll_p2_fck)) { | ||
528 | ret = PTR_ERR(omap->usbtll_p2_fck); | ||
529 | dev_err(omap->dev, | ||
530 | "Unable to get TLL CH1 clk\n"); | ||
531 | } else { | ||
532 | clk_enable(omap->usbtll_p2_fck); | ||
533 | } | ||
534 | break; | ||
535 | /* TODO */ | ||
536 | default: | ||
537 | break; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | /* perform TLL soft reset, and wait until reset is complete */ | ||
543 | ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
544 | OMAP_USBTLL_SYSCONFIG_SOFTRESET); | ||
545 | |||
546 | /* Wait for TLL reset to complete */ | ||
547 | while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
548 | & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { | ||
549 | cpu_relax(); | ||
550 | |||
551 | if (time_after(jiffies, timeout)) { | ||
552 | dev_dbg(omap->dev, "operation timed out\n"); | ||
553 | ret = -EINVAL; | ||
554 | goto err_sys_status; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | dev_dbg(omap->dev, "TLL RESET DONE\n"); | ||
559 | |||
560 | /* (1<<3) = no idle mode only for initial debugging */ | ||
561 | ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
562 | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | | ||
563 | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | | ||
564 | OMAP_USBTLL_SYSCONFIG_CACTIVITY); | ||
565 | |||
566 | |||
567 | /* Put UHH in NoIdle/NoStandby mode */ | ||
568 | reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); | ||
569 | if (is_omap_ehci_rev1(omap)) { | ||
570 | reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | ||
571 | | OMAP_UHH_SYSCONFIG_SIDLEMODE | ||
572 | | OMAP_UHH_SYSCONFIG_CACTIVITY | ||
573 | | OMAP_UHH_SYSCONFIG_MIDLEMODE); | ||
574 | reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; | ||
575 | |||
576 | |||
577 | } else if (is_omap_ehci_rev2(omap)) { | ||
578 | reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; | ||
579 | reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; | ||
580 | reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; | ||
581 | reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; | ||
582 | } | ||
583 | ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); | ||
584 | |||
585 | reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | ||
586 | |||
587 | /* setup ULPI bypass and burst configurations */ | ||
588 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | ||
589 | | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | ||
590 | | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); | ||
591 | reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; | ||
592 | |||
593 | if (is_omap_ehci_rev1(omap)) { | ||
594 | if (omap->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
595 | reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; | ||
596 | if (omap->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
597 | reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; | ||
598 | if (omap->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
599 | reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; | ||
600 | |||
601 | /* Bypass the TLL module for PHY mode operation */ | ||
602 | if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { | ||
603 | dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n"); | ||
604 | if (is_ehci_phy_mode(omap->port_mode[0]) || | ||
605 | is_ehci_phy_mode(omap->port_mode[1]) || | ||
606 | is_ehci_phy_mode(omap->port_mode[2])) | ||
607 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
608 | else | ||
609 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
610 | } else { | ||
611 | dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); | ||
612 | if (is_ehci_phy_mode(omap->port_mode[0])) | ||
613 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
614 | else if (is_ehci_tll_mode(omap->port_mode[0])) | ||
615 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
616 | |||
617 | if (is_ehci_phy_mode(omap->port_mode[1])) | ||
618 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
619 | else if (is_ehci_tll_mode(omap->port_mode[1])) | ||
620 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
621 | |||
622 | if (is_ehci_phy_mode(omap->port_mode[2])) | ||
623 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
624 | else if (is_ehci_tll_mode(omap->port_mode[2])) | ||
625 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
626 | } | ||
627 | } else if (is_omap_ehci_rev2(omap)) { | ||
628 | /* Clear port mode fields for PHY mode*/ | ||
629 | reg &= ~OMAP4_P1_MODE_CLEAR; | ||
630 | reg &= ~OMAP4_P2_MODE_CLEAR; | ||
631 | |||
632 | if (is_ehci_tll_mode(omap->port_mode[0])) | ||
633 | reg |= OMAP4_P1_MODE_TLL; | ||
634 | else if (is_ehci_hsic_mode(omap->port_mode[0])) | ||
635 | reg |= OMAP4_P1_MODE_HSIC; | ||
636 | |||
637 | if (is_ehci_tll_mode(omap->port_mode[1])) | ||
638 | reg |= OMAP4_P2_MODE_TLL; | ||
639 | else if (is_ehci_hsic_mode(omap->port_mode[1])) | ||
640 | reg |= OMAP4_P2_MODE_HSIC; | ||
641 | } | ||
642 | |||
643 | ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); | ||
644 | dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | ||
645 | |||
646 | |||
647 | /* | ||
648 | * An undocumented "feature" in the OMAP3 EHCI controller, | ||
649 | * causes suspended ports to be taken out of suspend when | ||
650 | * the USBCMD.Run/Stop bit is cleared (for example when | ||
651 | * we do ehci_bus_suspend). | ||
652 | * This breaks suspend-resume if the root-hub is allowed | ||
653 | * to suspend. Writing 1 to this undocumented register bit | ||
654 | * disables this feature and restores normal behavior. | ||
655 | */ | ||
656 | ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04, | ||
657 | EHCI_INSNREG04_DISABLE_UNSUSPEND); | ||
658 | |||
659 | if ((omap->port_mode[0] == OMAP_EHCI_PORT_MODE_TLL) || | ||
660 | (omap->port_mode[1] == OMAP_EHCI_PORT_MODE_TLL) || | ||
661 | (omap->port_mode[2] == OMAP_EHCI_PORT_MODE_TLL)) { | ||
662 | |||
663 | if (omap->port_mode[0] == OMAP_EHCI_PORT_MODE_TLL) | ||
664 | tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; | ||
665 | if (omap->port_mode[1] == OMAP_EHCI_PORT_MODE_TLL) | ||
666 | tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; | ||
667 | if (omap->port_mode[2] == OMAP_EHCI_PORT_MODE_TLL) | ||
668 | tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; | ||
669 | |||
670 | /* Enable UTMI mode for required TLL channels */ | ||
671 | omap_usb_utmi_init(omap, tll_ch_mask, OMAP_TLL_CHANNEL_COUNT); | ||
672 | } | ||
673 | |||
674 | if (omap->phy_reset) { | ||
675 | /* Refer ISSUE1: | ||
676 | * Hold the PHY in RESET for enough time till | ||
677 | * PHY is settled and ready | ||
678 | */ | ||
679 | udelay(10); | ||
680 | |||
681 | if (gpio_is_valid(omap->reset_gpio_port[0])) | ||
682 | gpio_set_value(omap->reset_gpio_port[0], 1); | ||
683 | |||
684 | if (gpio_is_valid(omap->reset_gpio_port[1])) | ||
685 | gpio_set_value(omap->reset_gpio_port[1], 1); | ||
686 | } | ||
687 | |||
688 | /* Soft reset the PHY using PHY reset command over ULPI */ | ||
689 | if (omap->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) | ||
690 | omap_ehci_soft_phy_reset(omap, 0); | ||
691 | if (omap->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) | ||
692 | omap_ehci_soft_phy_reset(omap, 1); | ||
693 | |||
694 | return 0; | ||
695 | |||
696 | err_sys_status: | ||
697 | |||
698 | if (omap->usbtll_p2_fck != NULL) { | ||
699 | clk_disable(omap->usbtll_p2_fck); | ||
700 | clk_put(omap->usbtll_p2_fck); | ||
701 | } | ||
702 | if (omap->usbhost_p2_fck != NULL) { | ||
703 | clk_disable(omap->usbhost_p2_fck); | ||
704 | clk_put(omap->usbhost_p2_fck); | ||
705 | } | ||
706 | if (omap->usbtll_p1_fck != NULL) { | ||
707 | clk_disable(omap->usbtll_p1_fck); | ||
708 | clk_put(omap->usbtll_p1_fck); | ||
709 | } | ||
710 | if (omap->usbhost_p1_fck != NULL) { | ||
711 | clk_disable(omap->usbhost_p1_fck); | ||
712 | clk_put(omap->usbhost_p1_fck); | ||
713 | } | ||
714 | |||
715 | clk_disable(omap->utmi_p2_fck); | ||
716 | clk_put(omap->utmi_p2_fck); | ||
717 | clk_disable(omap->xclk60mhsp2_ck); | ||
718 | clk_put(omap->xclk60mhsp2_ck); | ||
719 | clk_disable(omap->utmi_p1_fck); | ||
720 | clk_put(omap->utmi_p1_fck); | ||
721 | clk_disable(omap->xclk60mhsp1_ck); | ||
722 | clk_put(omap->xclk60mhsp1_ck); | ||
723 | clk_disable(omap->usbtll_ick); | ||
724 | clk_put(omap->usbtll_ick); | ||
725 | |||
726 | err_tll_ick: | ||
727 | clk_disable(omap->usbtll_fck); | ||
728 | clk_put(omap->usbtll_fck); | ||
729 | |||
730 | err_tll_fck: | ||
731 | clk_disable(omap->usbhost_fs_fck); | ||
732 | clk_put(omap->usbhost_fs_fck); | ||
733 | |||
734 | if (omap->phy_reset) { | ||
735 | if (gpio_is_valid(omap->reset_gpio_port[0])) | ||
736 | gpio_free(omap->reset_gpio_port[0]); | ||
737 | |||
738 | if (gpio_is_valid(omap->reset_gpio_port[1])) | ||
739 | gpio_free(omap->reset_gpio_port[1]); | ||
740 | } | ||
741 | |||
742 | err_host_48m_fck: | ||
743 | clk_disable(omap->usbhost_hs_fck); | ||
744 | clk_put(omap->usbhost_hs_fck); | ||
745 | |||
746 | err_host_120m_fck: | ||
747 | clk_disable(omap->usbhost_ick); | ||
748 | clk_put(omap->usbhost_ick); | ||
749 | |||
750 | err_host_ick: | ||
751 | return ret; | ||
752 | } | ||
753 | |||
754 | static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) | ||
755 | { | ||
756 | unsigned long timeout = jiffies + msecs_to_jiffies(100); | ||
757 | |||
758 | dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n"); | ||
759 | |||
760 | /* Reset OMAP modules for insmod/rmmod to work */ | ||
761 | ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, | ||
762 | is_omap_ehci_rev2(omap) ? | ||
763 | OMAP4_UHH_SYSCONFIG_SOFTRESET : | ||
764 | OMAP_UHH_SYSCONFIG_SOFTRESET); | ||
765 | while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
766 | & (1 << 0))) { | ||
767 | cpu_relax(); | ||
768 | |||
769 | if (time_after(jiffies, timeout)) | ||
770 | dev_dbg(omap->dev, "operation timed out\n"); | ||
771 | } | ||
772 | |||
773 | while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
774 | & (1 << 1))) { | ||
775 | cpu_relax(); | ||
776 | |||
777 | if (time_after(jiffies, timeout)) | ||
778 | dev_dbg(omap->dev, "operation timed out\n"); | ||
779 | } | ||
780 | |||
781 | while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
782 | & (1 << 2))) { | ||
783 | cpu_relax(); | ||
784 | |||
785 | if (time_after(jiffies, timeout)) | ||
786 | dev_dbg(omap->dev, "operation timed out\n"); | ||
787 | } | ||
788 | |||
789 | ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); | ||
790 | |||
791 | while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
792 | & (1 << 0))) { | ||
793 | cpu_relax(); | ||
794 | |||
795 | if (time_after(jiffies, timeout)) | ||
796 | dev_dbg(omap->dev, "operation timed out\n"); | ||
797 | } | ||
798 | |||
799 | if (omap->usbtll_fck != NULL) { | ||
800 | clk_disable(omap->usbtll_fck); | ||
801 | clk_put(omap->usbtll_fck); | ||
802 | omap->usbtll_fck = NULL; | ||
803 | } | ||
804 | |||
805 | if (omap->usbhost_ick != NULL) { | ||
806 | clk_disable(omap->usbhost_ick); | ||
807 | clk_put(omap->usbhost_ick); | ||
808 | omap->usbhost_ick = NULL; | ||
809 | } | ||
810 | |||
811 | if (omap->usbhost_fs_fck != NULL) { | ||
812 | clk_disable(omap->usbhost_fs_fck); | ||
813 | clk_put(omap->usbhost_fs_fck); | ||
814 | omap->usbhost_fs_fck = NULL; | ||
815 | } | ||
816 | |||
817 | if (omap->usbhost_hs_fck != NULL) { | ||
818 | clk_disable(omap->usbhost_hs_fck); | ||
819 | clk_put(omap->usbhost_hs_fck); | ||
820 | omap->usbhost_hs_fck = NULL; | ||
821 | } | ||
822 | |||
823 | if (omap->usbtll_ick != NULL) { | ||
824 | clk_disable(omap->usbtll_ick); | ||
825 | clk_put(omap->usbtll_ick); | ||
826 | omap->usbtll_ick = NULL; | ||
827 | } | ||
828 | |||
829 | if (is_omap_ehci_rev2(omap)) { | ||
830 | if (omap->xclk60mhsp1_ck != NULL) { | ||
831 | clk_disable(omap->xclk60mhsp1_ck); | ||
832 | clk_put(omap->xclk60mhsp1_ck); | ||
833 | omap->xclk60mhsp1_ck = NULL; | ||
834 | } | ||
835 | |||
836 | if (omap->utmi_p1_fck != NULL) { | ||
837 | clk_disable(omap->utmi_p1_fck); | ||
838 | clk_put(omap->utmi_p1_fck); | ||
839 | omap->utmi_p1_fck = NULL; | ||
840 | } | ||
841 | |||
842 | if (omap->xclk60mhsp2_ck != NULL) { | ||
843 | clk_disable(omap->xclk60mhsp2_ck); | ||
844 | clk_put(omap->xclk60mhsp2_ck); | ||
845 | omap->xclk60mhsp2_ck = NULL; | ||
846 | } | ||
847 | |||
848 | if (omap->utmi_p2_fck != NULL) { | ||
849 | clk_disable(omap->utmi_p2_fck); | ||
850 | clk_put(omap->utmi_p2_fck); | ||
851 | omap->utmi_p2_fck = NULL; | ||
852 | } | ||
853 | |||
854 | if (omap->usbtll_p2_fck != NULL) { | ||
855 | clk_disable(omap->usbtll_p2_fck); | ||
856 | clk_put(omap->usbtll_p2_fck); | ||
857 | omap->usbtll_p2_fck = NULL; | ||
858 | } | ||
859 | |||
860 | if (omap->usbhost_p2_fck != NULL) { | ||
861 | clk_disable(omap->usbhost_p2_fck); | ||
862 | clk_put(omap->usbhost_p2_fck); | ||
863 | omap->usbhost_p2_fck = NULL; | ||
864 | } | ||
865 | |||
866 | if (omap->usbtll_p1_fck != NULL) { | ||
867 | clk_disable(omap->usbtll_p1_fck); | ||
868 | clk_put(omap->usbtll_p1_fck); | ||
869 | omap->usbtll_p1_fck = NULL; | ||
870 | } | ||
871 | |||
872 | if (omap->usbhost_p1_fck != NULL) { | ||
873 | clk_disable(omap->usbhost_p1_fck); | ||
874 | clk_put(omap->usbhost_p1_fck); | ||
875 | omap->usbhost_p1_fck = NULL; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | if (omap->phy_reset) { | ||
880 | if (gpio_is_valid(omap->reset_gpio_port[0])) | ||
881 | gpio_free(omap->reset_gpio_port[0]); | ||
882 | |||
883 | if (gpio_is_valid(omap->reset_gpio_port[1])) | ||
884 | gpio_free(omap->reset_gpio_port[1]); | ||
885 | } | ||
886 | |||
887 | dev_dbg(omap->dev, "Clock to USB host has been disabled\n"); | ||
888 | } | ||
889 | |||
890 | /*-------------------------------------------------------------------------*/ | ||
891 | |||
892 | static const struct hc_driver ehci_omap_hc_driver; | ||
893 | 100 | ||
894 | /* configure so an HC device and id are always provided */ | 101 | /* configure so an HC device and id are always provided */ |
895 | /* always called with process context; sleeping is OK */ | 102 | /* always called with process context; sleeping is OK */ |
@@ -903,155 +110,113 @@ static const struct hc_driver ehci_omap_hc_driver; | |||
903 | */ | 110 | */ |
904 | static int ehci_hcd_omap_probe(struct platform_device *pdev) | 111 | static int ehci_hcd_omap_probe(struct platform_device *pdev) |
905 | { | 112 | { |
906 | struct usbhs_omap_board_data *pdata = pdev->dev.platform_data; | 113 | struct device *dev = &pdev->dev; |
907 | struct ehci_hcd_omap *omap; | 114 | struct ehci_hcd_omap_platform_data *pdata = dev->platform_data; |
908 | struct resource *res; | 115 | struct resource *res; |
909 | struct usb_hcd *hcd; | 116 | struct usb_hcd *hcd; |
117 | void __iomem *regs; | ||
118 | struct ehci_hcd *omap_ehci; | ||
119 | int ret = -ENODEV; | ||
120 | int irq; | ||
910 | 121 | ||
911 | int irq = platform_get_irq(pdev, 0); | 122 | if (usb_disabled()) |
912 | int ret = -ENODEV; | 123 | return -ENODEV; |
913 | int i; | ||
914 | char supply[7]; | ||
915 | 124 | ||
916 | if (!pdata) { | 125 | if (!dev->parent) { |
917 | dev_dbg(&pdev->dev, "missing platform_data\n"); | 126 | dev_err(dev, "Missing parent device\n"); |
918 | goto err_pdata; | 127 | return -ENODEV; |
919 | } | 128 | } |
920 | 129 | ||
921 | if (usb_disabled()) | 130 | irq = platform_get_irq_byname(pdev, "ehci-irq"); |
922 | goto err_disabled; | 131 | if (irq < 0) { |
132 | dev_err(dev, "EHCI irq failed\n"); | ||
133 | return -ENODEV; | ||
134 | } | ||
923 | 135 | ||
924 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); | 136 | res = platform_get_resource_byname(pdev, |
925 | if (!omap) { | 137 | IORESOURCE_MEM, "ehci"); |
926 | ret = -ENOMEM; | 138 | if (!res) { |
927 | goto err_disabled; | 139 | dev_err(dev, "UHH EHCI get resource failed\n"); |
140 | return -ENODEV; | ||
141 | } | ||
142 | |||
143 | regs = ioremap(res->start, resource_size(res)); | ||
144 | if (!regs) { | ||
145 | dev_err(dev, "UHH EHCI ioremap failed\n"); | ||
146 | return -ENOMEM; | ||
928 | } | 147 | } |
929 | 148 | ||
930 | hcd = usb_create_hcd(&ehci_omap_hc_driver, &pdev->dev, | 149 | hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, |
931 | dev_name(&pdev->dev)); | 150 | dev_name(dev)); |
932 | if (!hcd) { | 151 | if (!hcd) { |
933 | dev_err(&pdev->dev, "failed to create hcd with err %d\n", ret); | 152 | dev_err(dev, "failed to create hcd with err %d\n", ret); |
934 | ret = -ENOMEM; | 153 | ret = -ENOMEM; |
935 | goto err_create_hcd; | 154 | goto err_io; |
936 | } | 155 | } |
937 | 156 | ||
938 | platform_set_drvdata(pdev, omap); | ||
939 | omap->dev = &pdev->dev; | ||
940 | omap->phy_reset = pdata->phy_reset; | ||
941 | omap->reset_gpio_port[0] = pdata->reset_gpio_port[0]; | ||
942 | omap->reset_gpio_port[1] = pdata->reset_gpio_port[1]; | ||
943 | omap->reset_gpio_port[2] = pdata->reset_gpio_port[2]; | ||
944 | omap->port_mode[0] = pdata->port_mode[0]; | ||
945 | omap->port_mode[1] = pdata->port_mode[1]; | ||
946 | omap->port_mode[2] = pdata->port_mode[2]; | ||
947 | omap->ehci = hcd_to_ehci(hcd); | ||
948 | omap->ehci->sbrn = 0x20; | ||
949 | |||
950 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); | ||
951 | |||
952 | hcd->rsrc_start = res->start; | 157 | hcd->rsrc_start = res->start; |
953 | hcd->rsrc_len = resource_size(res); | 158 | hcd->rsrc_len = resource_size(res); |
159 | hcd->regs = regs; | ||
954 | 160 | ||
955 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | 161 | ret = omap_usbhs_enable(dev); |
956 | if (!hcd->regs) { | 162 | if (ret) { |
957 | dev_err(&pdev->dev, "EHCI ioremap failed\n"); | 163 | dev_err(dev, "failed to start usbhs with err %d\n", ret); |
958 | ret = -ENOMEM; | 164 | goto err_enable; |
959 | goto err_ioremap; | ||
960 | } | ||
961 | |||
962 | /* we know this is the memory we want, no need to ioremap again */ | ||
963 | omap->ehci->caps = hcd->regs; | ||
964 | omap->ehci_base = hcd->regs; | ||
965 | |||
966 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | ||
967 | omap->uhh_base = ioremap(res->start, resource_size(res)); | ||
968 | if (!omap->uhh_base) { | ||
969 | dev_err(&pdev->dev, "UHH ioremap failed\n"); | ||
970 | ret = -ENOMEM; | ||
971 | goto err_uhh_ioremap; | ||
972 | } | 165 | } |
973 | 166 | ||
974 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); | 167 | /* |
975 | omap->tll_base = ioremap(res->start, resource_size(res)); | 168 | * An undocumented "feature" in the OMAP3 EHCI controller, |
976 | if (!omap->tll_base) { | 169 | * causes suspended ports to be taken out of suspend when |
977 | dev_err(&pdev->dev, "TLL ioremap failed\n"); | 170 | * the USBCMD.Run/Stop bit is cleared (for example when |
978 | ret = -ENOMEM; | 171 | * we do ehci_bus_suspend). |
979 | goto err_tll_ioremap; | 172 | * This breaks suspend-resume if the root-hub is allowed |
980 | } | 173 | * to suspend. Writing 1 to this undocumented register bit |
174 | * disables this feature and restores normal behavior. | ||
175 | */ | ||
176 | ehci_write(regs, EHCI_INSNREG04, | ||
177 | EHCI_INSNREG04_DISABLE_UNSUSPEND); | ||
981 | 178 | ||
982 | /* get ehci regulator and enable */ | 179 | /* Soft reset the PHY using PHY reset command over ULPI */ |
983 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { | 180 | if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) |
984 | if (omap->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { | 181 | omap_ehci_soft_phy_reset(pdev, 0); |
985 | omap->regulator[i] = NULL; | 182 | if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) |
986 | continue; | 183 | omap_ehci_soft_phy_reset(pdev, 1); |
987 | } | ||
988 | snprintf(supply, sizeof(supply), "hsusb%d", i); | ||
989 | omap->regulator[i] = regulator_get(omap->dev, supply); | ||
990 | if (IS_ERR(omap->regulator[i])) { | ||
991 | omap->regulator[i] = NULL; | ||
992 | dev_dbg(&pdev->dev, | ||
993 | "failed to get ehci port%d regulator\n", i); | ||
994 | } else { | ||
995 | regulator_enable(omap->regulator[i]); | ||
996 | } | ||
997 | } | ||
998 | 184 | ||
999 | ret = omap_start_ehc(omap, hcd); | 185 | omap_ehci = hcd_to_ehci(hcd); |
1000 | if (ret) { | 186 | omap_ehci->sbrn = 0x20; |
1001 | dev_err(&pdev->dev, "failed to start ehci with err %d\n", ret); | ||
1002 | goto err_start; | ||
1003 | } | ||
1004 | 187 | ||
1005 | omap->ehci->regs = hcd->regs | 188 | /* we know this is the memory we want, no need to ioremap again */ |
1006 | + HC_LENGTH(readl(&omap->ehci->caps->hc_capbase)); | 189 | omap_ehci->caps = hcd->regs; |
190 | omap_ehci->regs = hcd->regs | ||
191 | + HC_LENGTH(readl(&omap_ehci->caps->hc_capbase)); | ||
1007 | 192 | ||
1008 | dbg_hcs_params(omap->ehci, "reset"); | 193 | dbg_hcs_params(omap_ehci, "reset"); |
1009 | dbg_hcc_params(omap->ehci, "reset"); | 194 | dbg_hcc_params(omap_ehci, "reset"); |
1010 | 195 | ||
1011 | /* cache this readonly data; minimize chip reads */ | 196 | /* cache this readonly data; minimize chip reads */ |
1012 | omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params); | 197 | omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params); |
1013 | 198 | ||
1014 | ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); | 199 | ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); |
1015 | if (ret) { | 200 | if (ret) { |
1016 | dev_err(&pdev->dev, "failed to add hcd with err %d\n", ret); | 201 | dev_err(dev, "failed to add hcd with err %d\n", ret); |
1017 | goto err_add_hcd; | 202 | goto err_add_hcd; |
1018 | } | 203 | } |
1019 | 204 | ||
1020 | /* root ports should always stay powered */ | 205 | /* root ports should always stay powered */ |
1021 | ehci_port_power(omap->ehci, 1); | 206 | ehci_port_power(omap_ehci, 1); |
1022 | 207 | ||
1023 | return 0; | 208 | return 0; |
1024 | 209 | ||
1025 | err_add_hcd: | 210 | err_add_hcd: |
1026 | omap_stop_ehc(omap, hcd); | 211 | omap_usbhs_disable(dev); |
1027 | 212 | ||
1028 | err_start: | 213 | err_enable: |
1029 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { | ||
1030 | if (omap->regulator[i]) { | ||
1031 | regulator_disable(omap->regulator[i]); | ||
1032 | regulator_put(omap->regulator[i]); | ||
1033 | } | ||
1034 | } | ||
1035 | iounmap(omap->tll_base); | ||
1036 | |||
1037 | err_tll_ioremap: | ||
1038 | iounmap(omap->uhh_base); | ||
1039 | |||
1040 | err_uhh_ioremap: | ||
1041 | iounmap(hcd->regs); | ||
1042 | |||
1043 | err_ioremap: | ||
1044 | usb_put_hcd(hcd); | 214 | usb_put_hcd(hcd); |
1045 | 215 | ||
1046 | err_create_hcd: | 216 | err_io: |
1047 | kfree(omap); | ||
1048 | err_disabled: | ||
1049 | err_pdata: | ||
1050 | return ret; | 217 | return ret; |
1051 | } | 218 | } |
1052 | 219 | ||
1053 | /* may be called without controller electrically present */ | ||
1054 | /* may be called with controller, bus, and devices active */ | ||
1055 | 220 | ||
1056 | /** | 221 | /** |
1057 | * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs | 222 | * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs |
@@ -1063,31 +228,18 @@ err_pdata: | |||
1063 | */ | 228 | */ |
1064 | static int ehci_hcd_omap_remove(struct platform_device *pdev) | 229 | static int ehci_hcd_omap_remove(struct platform_device *pdev) |
1065 | { | 230 | { |
1066 | struct ehci_hcd_omap *omap = platform_get_drvdata(pdev); | 231 | struct device *dev = &pdev->dev; |
1067 | struct usb_hcd *hcd = ehci_to_hcd(omap->ehci); | 232 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
1068 | int i; | ||
1069 | 233 | ||
1070 | usb_remove_hcd(hcd); | 234 | usb_remove_hcd(hcd); |
1071 | omap_stop_ehc(omap, hcd); | 235 | omap_usbhs_disable(dev); |
1072 | iounmap(hcd->regs); | ||
1073 | for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { | ||
1074 | if (omap->regulator[i]) { | ||
1075 | regulator_disable(omap->regulator[i]); | ||
1076 | regulator_put(omap->regulator[i]); | ||
1077 | } | ||
1078 | } | ||
1079 | iounmap(omap->tll_base); | ||
1080 | iounmap(omap->uhh_base); | ||
1081 | usb_put_hcd(hcd); | 236 | usb_put_hcd(hcd); |
1082 | kfree(omap); | ||
1083 | |||
1084 | return 0; | 237 | return 0; |
1085 | } | 238 | } |
1086 | 239 | ||
1087 | static void ehci_hcd_omap_shutdown(struct platform_device *pdev) | 240 | static void ehci_hcd_omap_shutdown(struct platform_device *pdev) |
1088 | { | 241 | { |
1089 | struct ehci_hcd_omap *omap = platform_get_drvdata(pdev); | 242 | struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); |
1090 | struct usb_hcd *hcd = ehci_to_hcd(omap->ehci); | ||
1091 | 243 | ||
1092 | if (hcd->driver->shutdown) | 244 | if (hcd->driver->shutdown) |
1093 | hcd->driver->shutdown(hcd); | 245 | hcd->driver->shutdown(hcd); |