diff options
-rw-r--r-- | drivers/mfd/omap-usb-host.c | 558 | ||||
-rw-r--r-- | drivers/mfd/omap-usb-tll.c | 243 | ||||
-rw-r--r-- | drivers/usb/host/ehci-omap.c | 6 | ||||
-rw-r--r-- | include/linux/platform_data/usb-omap.h | 1 |
4 files changed, 470 insertions, 338 deletions
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 05164d7f054b..6b5edf64de2b 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
28 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
29 | #include <linux/platform_data/usb-omap.h> | 28 | #include <linux/platform_data/usb-omap.h> |
@@ -91,21 +90,23 @@ | |||
91 | 90 | ||
92 | 91 | ||
93 | struct usbhs_hcd_omap { | 92 | struct usbhs_hcd_omap { |
93 | int nports; | ||
94 | struct clk **utmi_clk; | ||
95 | struct clk **hsic60m_clk; | ||
96 | struct clk **hsic480m_clk; | ||
97 | |||
94 | struct clk *xclk60mhsp1_ck; | 98 | struct clk *xclk60mhsp1_ck; |
95 | struct clk *xclk60mhsp2_ck; | 99 | struct clk *xclk60mhsp2_ck; |
96 | struct clk *utmi_p1_fck; | 100 | struct clk *utmi_p1_gfclk; |
97 | struct clk *usbhost_p1_fck; | 101 | struct clk *utmi_p2_gfclk; |
98 | struct clk *utmi_p2_fck; | ||
99 | struct clk *usbhost_p2_fck; | ||
100 | struct clk *init_60m_fclk; | 102 | struct clk *init_60m_fclk; |
101 | struct clk *ehci_logic_fck; | 103 | struct clk *ehci_logic_fck; |
102 | 104 | ||
103 | void __iomem *uhh_base; | 105 | void __iomem *uhh_base; |
104 | 106 | ||
105 | struct usbhs_omap_platform_data platdata; | 107 | struct usbhs_omap_platform_data *pdata; |
106 | 108 | ||
107 | u32 usbhs_rev; | 109 | u32 usbhs_rev; |
108 | spinlock_t lock; | ||
109 | }; | 110 | }; |
110 | /*-------------------------------------------------------------------------*/ | 111 | /*-------------------------------------------------------------------------*/ |
111 | 112 | ||
@@ -184,19 +185,13 @@ err_end: | |||
184 | static int omap_usbhs_alloc_children(struct platform_device *pdev) | 185 | static int omap_usbhs_alloc_children(struct platform_device *pdev) |
185 | { | 186 | { |
186 | struct device *dev = &pdev->dev; | 187 | struct device *dev = &pdev->dev; |
187 | struct usbhs_hcd_omap *omap; | 188 | struct usbhs_omap_platform_data *pdata = dev->platform_data; |
188 | struct ehci_hcd_omap_platform_data *ehci_data; | ||
189 | struct ohci_hcd_omap_platform_data *ohci_data; | ||
190 | struct platform_device *ehci; | 189 | struct platform_device *ehci; |
191 | struct platform_device *ohci; | 190 | struct platform_device *ohci; |
192 | struct resource *res; | 191 | struct resource *res; |
193 | struct resource resources[2]; | 192 | struct resource resources[2]; |
194 | int ret; | 193 | int ret; |
195 | 194 | ||
196 | omap = platform_get_drvdata(pdev); | ||
197 | ehci_data = omap->platdata.ehci_data; | ||
198 | ohci_data = omap->platdata.ohci_data; | ||
199 | |||
200 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); | 195 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); |
201 | if (!res) { | 196 | if (!res) { |
202 | dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n"); | 197 | dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n"); |
@@ -213,8 +208,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) | |||
213 | } | 208 | } |
214 | resources[1] = *res; | 209 | resources[1] = *res; |
215 | 210 | ||
216 | ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data, | 211 | ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata, |
217 | sizeof(*ehci_data), dev); | 212 | sizeof(*pdata), dev); |
218 | 213 | ||
219 | if (!ehci) { | 214 | if (!ehci) { |
220 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); | 215 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); |
@@ -238,8 +233,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) | |||
238 | } | 233 | } |
239 | resources[1] = *res; | 234 | resources[1] = *res; |
240 | 235 | ||
241 | ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data, | 236 | ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata, |
242 | sizeof(*ohci_data), dev); | 237 | sizeof(*pdata), dev); |
243 | if (!ohci) { | 238 | if (!ohci) { |
244 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); | 239 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); |
245 | ret = -ENOMEM; | 240 | ret = -ENOMEM; |
@@ -278,31 +273,52 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) | |||
278 | static int usbhs_runtime_resume(struct device *dev) | 273 | static int usbhs_runtime_resume(struct device *dev) |
279 | { | 274 | { |
280 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 275 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
281 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 276 | struct usbhs_omap_platform_data *pdata = omap->pdata; |
282 | unsigned long flags; | 277 | int i, r; |
283 | 278 | ||
284 | dev_dbg(dev, "usbhs_runtime_resume\n"); | 279 | dev_dbg(dev, "usbhs_runtime_resume\n"); |
285 | 280 | ||
286 | if (!pdata) { | ||
287 | dev_dbg(dev, "missing platform_data\n"); | ||
288 | return -ENODEV; | ||
289 | } | ||
290 | |||
291 | omap_tll_enable(); | 281 | omap_tll_enable(); |
292 | spin_lock_irqsave(&omap->lock, flags); | ||
293 | 282 | ||
294 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) | 283 | if (!IS_ERR(omap->ehci_logic_fck)) |
295 | clk_enable(omap->ehci_logic_fck); | 284 | clk_enable(omap->ehci_logic_fck); |
296 | 285 | ||
297 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 286 | for (i = 0; i < omap->nports; i++) { |
298 | clk_enable(omap->usbhost_p1_fck); | 287 | switch (pdata->port_mode[i]) { |
299 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 288 | case OMAP_EHCI_PORT_MODE_HSIC: |
300 | clk_enable(omap->usbhost_p2_fck); | 289 | if (!IS_ERR(omap->hsic60m_clk[i])) { |
301 | 290 | r = clk_enable(omap->hsic60m_clk[i]); | |
302 | clk_enable(omap->utmi_p1_fck); | 291 | if (r) { |
303 | clk_enable(omap->utmi_p2_fck); | 292 | dev_err(dev, |
293 | "Can't enable port %d hsic60m clk:%d\n", | ||
294 | i, r); | ||
295 | } | ||
296 | } | ||
304 | 297 | ||
305 | spin_unlock_irqrestore(&omap->lock, flags); | 298 | if (!IS_ERR(omap->hsic480m_clk[i])) { |
299 | r = clk_enable(omap->hsic480m_clk[i]); | ||
300 | if (r) { | ||
301 | dev_err(dev, | ||
302 | "Can't enable port %d hsic480m clk:%d\n", | ||
303 | i, r); | ||
304 | } | ||
305 | } | ||
306 | /* Fall through as HSIC mode needs utmi_clk */ | ||
307 | |||
308 | case OMAP_EHCI_PORT_MODE_TLL: | ||
309 | if (!IS_ERR(omap->utmi_clk[i])) { | ||
310 | r = clk_enable(omap->utmi_clk[i]); | ||
311 | if (r) { | ||
312 | dev_err(dev, | ||
313 | "Can't enable port %d clk : %d\n", | ||
314 | i, r); | ||
315 | } | ||
316 | } | ||
317 | break; | ||
318 | default: | ||
319 | break; | ||
320 | } | ||
321 | } | ||
306 | 322 | ||
307 | return 0; | 323 | return 0; |
308 | } | 324 | } |
@@ -310,51 +326,122 @@ static int usbhs_runtime_resume(struct device *dev) | |||
310 | static int usbhs_runtime_suspend(struct device *dev) | 326 | static int usbhs_runtime_suspend(struct device *dev) |
311 | { | 327 | { |
312 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 328 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
313 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 329 | struct usbhs_omap_platform_data *pdata = omap->pdata; |
314 | unsigned long flags; | 330 | int i; |
315 | 331 | ||
316 | dev_dbg(dev, "usbhs_runtime_suspend\n"); | 332 | dev_dbg(dev, "usbhs_runtime_suspend\n"); |
317 | 333 | ||
318 | if (!pdata) { | 334 | for (i = 0; i < omap->nports; i++) { |
319 | dev_dbg(dev, "missing platform_data\n"); | 335 | switch (pdata->port_mode[i]) { |
320 | return -ENODEV; | 336 | case OMAP_EHCI_PORT_MODE_HSIC: |
321 | } | 337 | if (!IS_ERR(omap->hsic60m_clk[i])) |
322 | 338 | clk_disable(omap->hsic60m_clk[i]); | |
323 | spin_lock_irqsave(&omap->lock, flags); | ||
324 | 339 | ||
325 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 340 | if (!IS_ERR(omap->hsic480m_clk[i])) |
326 | clk_disable(omap->usbhost_p1_fck); | 341 | clk_disable(omap->hsic480m_clk[i]); |
327 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 342 | /* Fall through as utmi_clks were used in HSIC mode */ |
328 | clk_disable(omap->usbhost_p2_fck); | ||
329 | 343 | ||
330 | clk_disable(omap->utmi_p2_fck); | 344 | case OMAP_EHCI_PORT_MODE_TLL: |
331 | clk_disable(omap->utmi_p1_fck); | 345 | if (!IS_ERR(omap->utmi_clk[i])) |
346 | clk_disable(omap->utmi_clk[i]); | ||
347 | break; | ||
348 | default: | ||
349 | break; | ||
350 | } | ||
351 | } | ||
332 | 352 | ||
333 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) | 353 | if (!IS_ERR(omap->ehci_logic_fck)) |
334 | clk_disable(omap->ehci_logic_fck); | 354 | clk_disable(omap->ehci_logic_fck); |
335 | 355 | ||
336 | spin_unlock_irqrestore(&omap->lock, flags); | ||
337 | omap_tll_disable(); | 356 | omap_tll_disable(); |
338 | 357 | ||
339 | return 0; | 358 | return 0; |
340 | } | 359 | } |
341 | 360 | ||
361 | static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap, | ||
362 | unsigned reg) | ||
363 | { | ||
364 | struct usbhs_omap_platform_data *pdata = omap->pdata; | ||
365 | int i; | ||
366 | |||
367 | for (i = 0; i < omap->nports; i++) { | ||
368 | switch (pdata->port_mode[i]) { | ||
369 | case OMAP_USBHS_PORT_MODE_UNUSED: | ||
370 | reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i); | ||
371 | break; | ||
372 | case OMAP_EHCI_PORT_MODE_PHY: | ||
373 | if (pdata->single_ulpi_bypass) | ||
374 | break; | ||
375 | |||
376 | if (i == 0) | ||
377 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
378 | else | ||
379 | reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS | ||
380 | << (i-1)); | ||
381 | break; | ||
382 | default: | ||
383 | if (pdata->single_ulpi_bypass) | ||
384 | break; | ||
385 | |||
386 | if (i == 0) | ||
387 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
388 | else | ||
389 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS | ||
390 | << (i-1); | ||
391 | break; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | if (pdata->single_ulpi_bypass) { | ||
396 | /* bypass ULPI only if none of the ports use PHY mode */ | ||
397 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
398 | |||
399 | for (i = 0; i < omap->nports; i++) { | ||
400 | if (is_ehci_phy_mode(pdata->port_mode[i])) { | ||
401 | reg &= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
402 | break; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | return reg; | ||
408 | } | ||
409 | |||
410 | static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap, | ||
411 | unsigned reg) | ||
412 | { | ||
413 | struct usbhs_omap_platform_data *pdata = omap->pdata; | ||
414 | int i; | ||
415 | |||
416 | for (i = 0; i < omap->nports; i++) { | ||
417 | /* Clear port mode fields for PHY mode */ | ||
418 | reg &= ~(OMAP4_P1_MODE_CLEAR << 2 * i); | ||
419 | |||
420 | if (is_ehci_tll_mode(pdata->port_mode[i]) || | ||
421 | (is_ohci_port(pdata->port_mode[i]))) | ||
422 | reg |= OMAP4_P1_MODE_TLL << 2 * i; | ||
423 | else if (is_ehci_hsic_mode(pdata->port_mode[i])) | ||
424 | reg |= OMAP4_P1_MODE_HSIC << 2 * i; | ||
425 | } | ||
426 | |||
427 | return reg; | ||
428 | } | ||
429 | |||
342 | static void omap_usbhs_init(struct device *dev) | 430 | static void omap_usbhs_init(struct device *dev) |
343 | { | 431 | { |
344 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 432 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
345 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 433 | struct usbhs_omap_platform_data *pdata = omap->pdata; |
346 | unsigned long flags; | ||
347 | unsigned reg; | 434 | unsigned reg; |
348 | 435 | ||
349 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | 436 | dev_dbg(dev, "starting TI HSUSB Controller\n"); |
350 | 437 | ||
351 | if (pdata->ehci_data->phy_reset) { | 438 | if (pdata->phy_reset) { |
352 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 439 | if (gpio_is_valid(pdata->reset_gpio_port[0])) |
353 | gpio_request_one(pdata->ehci_data->reset_gpio_port[0], | 440 | gpio_request_one(pdata->reset_gpio_port[0], |
354 | GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); | 441 | GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); |
355 | 442 | ||
356 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 443 | if (gpio_is_valid(pdata->reset_gpio_port[1])) |
357 | gpio_request_one(pdata->ehci_data->reset_gpio_port[1], | 444 | gpio_request_one(pdata->reset_gpio_port[1], |
358 | GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); | 445 | GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); |
359 | 446 | ||
360 | /* Hold the PHY in RESET for enough time till DIR is high */ | 447 | /* Hold the PHY in RESET for enough time till DIR is high */ |
@@ -362,9 +449,6 @@ static void omap_usbhs_init(struct device *dev) | |||
362 | } | 449 | } |
363 | 450 | ||
364 | pm_runtime_get_sync(dev); | 451 | pm_runtime_get_sync(dev); |
365 | spin_lock_irqsave(&omap->lock, flags); | ||
366 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | ||
367 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | ||
368 | 452 | ||
369 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | 453 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); |
370 | /* setup ULPI bypass and burst configurations */ | 454 | /* setup ULPI bypass and burst configurations */ |
@@ -374,89 +458,51 @@ static void omap_usbhs_init(struct device *dev) | |||
374 | reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; | 458 | reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; |
375 | reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; | 459 | reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; |
376 | 460 | ||
377 | if (is_omap_usbhs_rev1(omap)) { | 461 | switch (omap->usbhs_rev) { |
378 | if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) | 462 | case OMAP_USBHS_REV1: |
379 | reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; | 463 | omap_usbhs_rev1_hostconfig(omap, reg); |
380 | if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) | 464 | break; |
381 | reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; | ||
382 | if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
383 | reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; | ||
384 | |||
385 | /* Bypass the TLL module for PHY mode operation */ | ||
386 | if (pdata->single_ulpi_bypass) { | ||
387 | dev_dbg(dev, "OMAP3 ES version <= ES2.1\n"); | ||
388 | if (is_ehci_phy_mode(pdata->port_mode[0]) || | ||
389 | is_ehci_phy_mode(pdata->port_mode[1]) || | ||
390 | is_ehci_phy_mode(pdata->port_mode[2])) | ||
391 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
392 | else | ||
393 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
394 | } else { | ||
395 | dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); | ||
396 | if (is_ehci_phy_mode(pdata->port_mode[0])) | ||
397 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
398 | else | ||
399 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
400 | if (is_ehci_phy_mode(pdata->port_mode[1])) | ||
401 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
402 | else | ||
403 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
404 | if (is_ehci_phy_mode(pdata->port_mode[2])) | ||
405 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
406 | else | ||
407 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
408 | } | ||
409 | } else if (is_omap_usbhs_rev2(omap)) { | ||
410 | /* Clear port mode fields for PHY mode*/ | ||
411 | reg &= ~OMAP4_P1_MODE_CLEAR; | ||
412 | reg &= ~OMAP4_P2_MODE_CLEAR; | ||
413 | 465 | ||
414 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | 466 | case OMAP_USBHS_REV2: |
415 | (is_ohci_port(pdata->port_mode[0]))) | 467 | omap_usbhs_rev2_hostconfig(omap, reg); |
416 | reg |= OMAP4_P1_MODE_TLL; | 468 | break; |
417 | else if (is_ehci_hsic_mode(pdata->port_mode[0])) | ||
418 | reg |= OMAP4_P1_MODE_HSIC; | ||
419 | 469 | ||
420 | if (is_ehci_tll_mode(pdata->port_mode[1]) || | 470 | default: /* newer revisions */ |
421 | (is_ohci_port(pdata->port_mode[1]))) | 471 | omap_usbhs_rev2_hostconfig(omap, reg); |
422 | reg |= OMAP4_P2_MODE_TLL; | 472 | break; |
423 | else if (is_ehci_hsic_mode(pdata->port_mode[1])) | ||
424 | reg |= OMAP4_P2_MODE_HSIC; | ||
425 | } | 473 | } |
426 | 474 | ||
427 | usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); | 475 | usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); |
428 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | 476 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); |
429 | 477 | ||
430 | spin_unlock_irqrestore(&omap->lock, flags); | ||
431 | |||
432 | pm_runtime_put_sync(dev); | 478 | pm_runtime_put_sync(dev); |
433 | if (pdata->ehci_data->phy_reset) { | 479 | if (pdata->phy_reset) { |
434 | /* Hold the PHY in RESET for enough time till | 480 | /* Hold the PHY in RESET for enough time till |
435 | * PHY is settled and ready | 481 | * PHY is settled and ready |
436 | */ | 482 | */ |
437 | udelay(10); | 483 | udelay(10); |
438 | 484 | ||
439 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 485 | if (gpio_is_valid(pdata->reset_gpio_port[0])) |
440 | gpio_set_value_cansleep | 486 | gpio_set_value_cansleep |
441 | (pdata->ehci_data->reset_gpio_port[0], 1); | 487 | (pdata->reset_gpio_port[0], 1); |
442 | 488 | ||
443 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 489 | if (gpio_is_valid(pdata->reset_gpio_port[1])) |
444 | gpio_set_value_cansleep | 490 | gpio_set_value_cansleep |
445 | (pdata->ehci_data->reset_gpio_port[1], 1); | 491 | (pdata->reset_gpio_port[1], 1); |
446 | } | 492 | } |
447 | } | 493 | } |
448 | 494 | ||
449 | static void omap_usbhs_deinit(struct device *dev) | 495 | static void omap_usbhs_deinit(struct device *dev) |
450 | { | 496 | { |
451 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 497 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
452 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 498 | struct usbhs_omap_platform_data *pdata = omap->pdata; |
453 | 499 | ||
454 | if (pdata->ehci_data->phy_reset) { | 500 | if (pdata->phy_reset) { |
455 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 501 | if (gpio_is_valid(pdata->reset_gpio_port[0])) |
456 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | 502 | gpio_free(pdata->reset_gpio_port[0]); |
457 | 503 | ||
458 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 504 | if (gpio_is_valid(pdata->reset_gpio_port[1])) |
459 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | 505 | gpio_free(pdata->reset_gpio_port[1]); |
460 | } | 506 | } |
461 | } | 507 | } |
462 | 508 | ||
@@ -474,137 +520,185 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
474 | struct resource *res; | 520 | struct resource *res; |
475 | int ret = 0; | 521 | int ret = 0; |
476 | int i; | 522 | int i; |
523 | bool need_logic_fck; | ||
477 | 524 | ||
478 | if (!pdata) { | 525 | if (!pdata) { |
479 | dev_err(dev, "Missing platform data\n"); | 526 | dev_err(dev, "Missing platform data\n"); |
480 | ret = -ENOMEM; | 527 | return -ENODEV; |
481 | goto end_probe; | ||
482 | } | 528 | } |
483 | 529 | ||
484 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); | 530 | omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); |
485 | if (!omap) { | 531 | if (!omap) { |
486 | dev_err(dev, "Memory allocation failed\n"); | 532 | dev_err(dev, "Memory allocation failed\n"); |
487 | ret = -ENOMEM; | 533 | return -ENOMEM; |
488 | goto end_probe; | ||
489 | } | 534 | } |
490 | 535 | ||
491 | spin_lock_init(&omap->lock); | 536 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); |
492 | 537 | omap->uhh_base = devm_request_and_ioremap(dev, res); | |
493 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | 538 | if (!omap->uhh_base) { |
494 | omap->platdata.port_mode[i] = pdata->port_mode[i]; | 539 | dev_err(dev, "Resource request/ioremap failed\n"); |
540 | return -EADDRNOTAVAIL; | ||
541 | } | ||
495 | 542 | ||
496 | omap->platdata.ehci_data = pdata->ehci_data; | 543 | omap->pdata = pdata; |
497 | omap->platdata.ohci_data = pdata->ohci_data; | ||
498 | 544 | ||
499 | pm_runtime_enable(dev); | 545 | pm_runtime_enable(dev); |
500 | 546 | ||
547 | platform_set_drvdata(pdev, omap); | ||
548 | pm_runtime_get_sync(dev); | ||
549 | |||
550 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | ||
501 | 551 | ||
502 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | 552 | /* we need to call runtime suspend before we update omap->nports |
503 | if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || | 553 | * to prevent unbalanced clk_disable() |
504 | is_ehci_hsic_mode(i)) { | 554 | */ |
505 | omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); | 555 | pm_runtime_put_sync(dev); |
506 | if (IS_ERR(omap->ehci_logic_fck)) { | 556 | |
507 | ret = PTR_ERR(omap->ehci_logic_fck); | 557 | /* |
508 | dev_warn(dev, "ehci_logic_fck failed:%d\n", | 558 | * If platform data contains nports then use that |
509 | ret); | 559 | * else make out number of ports from USBHS revision |
510 | } | 560 | */ |
561 | if (pdata->nports) { | ||
562 | omap->nports = pdata->nports; | ||
563 | } else { | ||
564 | switch (omap->usbhs_rev) { | ||
565 | case OMAP_USBHS_REV1: | ||
566 | omap->nports = 3; | ||
567 | break; | ||
568 | case OMAP_USBHS_REV2: | ||
569 | omap->nports = 2; | ||
570 | break; | ||
571 | default: | ||
572 | omap->nports = OMAP3_HS_USB_PORTS; | ||
573 | dev_dbg(dev, | ||
574 | "USB HOST Rev:0x%d not recognized, assuming %d ports\n", | ||
575 | omap->usbhs_rev, omap->nports); | ||
511 | break; | 576 | break; |
512 | } | 577 | } |
578 | } | ||
513 | 579 | ||
514 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | 580 | i = sizeof(struct clk *) * omap->nports; |
515 | if (IS_ERR(omap->utmi_p1_fck)) { | 581 | omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL); |
516 | ret = PTR_ERR(omap->utmi_p1_fck); | 582 | omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL); |
517 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | 583 | omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL); |
518 | goto err_end; | 584 | |
585 | if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) { | ||
586 | dev_err(dev, "Memory allocation failed\n"); | ||
587 | ret = -ENOMEM; | ||
588 | goto err_mem; | ||
589 | } | ||
590 | |||
591 | need_logic_fck = false; | ||
592 | for (i = 0; i < omap->nports; i++) { | ||
593 | if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || | ||
594 | is_ehci_hsic_mode(i)) | ||
595 | need_logic_fck |= true; | ||
596 | } | ||
597 | |||
598 | omap->ehci_logic_fck = ERR_PTR(-EINVAL); | ||
599 | if (need_logic_fck) { | ||
600 | omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); | ||
601 | if (IS_ERR(omap->ehci_logic_fck)) { | ||
602 | ret = PTR_ERR(omap->ehci_logic_fck); | ||
603 | dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk"); | ||
608 | if (IS_ERR(omap->utmi_p1_gfclk)) { | ||
609 | ret = PTR_ERR(omap->utmi_p1_gfclk); | ||
610 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | ||
611 | goto err_p1_gfclk; | ||
612 | } | ||
613 | |||
614 | omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk"); | ||
615 | if (IS_ERR(omap->utmi_p2_gfclk)) { | ||
616 | ret = PTR_ERR(omap->utmi_p2_gfclk); | ||
617 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
618 | goto err_p2_gfclk; | ||
519 | } | 619 | } |
520 | 620 | ||
521 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | 621 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); |
522 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | 622 | if (IS_ERR(omap->xclk60mhsp1_ck)) { |
523 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | 623 | ret = PTR_ERR(omap->xclk60mhsp1_ck); |
524 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); | 624 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); |
525 | goto err_utmi_p1_fck; | 625 | goto err_xclk60mhsp1; |
526 | } | ||
527 | |||
528 | omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); | ||
529 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
530 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
531 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
532 | goto err_xclk60mhsp1_ck; | ||
533 | } | 626 | } |
534 | 627 | ||
535 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); | 628 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); |
536 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | 629 | if (IS_ERR(omap->xclk60mhsp2_ck)) { |
537 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | 630 | ret = PTR_ERR(omap->xclk60mhsp2_ck); |
538 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); | 631 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); |
539 | goto err_utmi_p2_fck; | 632 | goto err_xclk60mhsp2; |
540 | } | ||
541 | |||
542 | omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); | ||
543 | if (IS_ERR(omap->usbhost_p1_fck)) { | ||
544 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
545 | dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); | ||
546 | goto err_xclk60mhsp2_ck; | ||
547 | } | ||
548 | |||
549 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); | ||
550 | if (IS_ERR(omap->usbhost_p2_fck)) { | ||
551 | ret = PTR_ERR(omap->usbhost_p2_fck); | ||
552 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | ||
553 | goto err_usbhost_p1_fck; | ||
554 | } | 633 | } |
555 | 634 | ||
556 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); | 635 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); |
557 | if (IS_ERR(omap->init_60m_fclk)) { | 636 | if (IS_ERR(omap->init_60m_fclk)) { |
558 | ret = PTR_ERR(omap->init_60m_fclk); | 637 | ret = PTR_ERR(omap->init_60m_fclk); |
559 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); | 638 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); |
560 | goto err_usbhost_p2_fck; | 639 | goto err_init60m; |
640 | } | ||
641 | |||
642 | for (i = 0; i < omap->nports; i++) { | ||
643 | char clkname[30]; | ||
644 | |||
645 | /* clock names are indexed from 1*/ | ||
646 | snprintf(clkname, sizeof(clkname), | ||
647 | "usb_host_hs_utmi_p%d_clk", i + 1); | ||
648 | |||
649 | /* If a clock is not found we won't bail out as not all | ||
650 | * platforms have all clocks and we can function without | ||
651 | * them | ||
652 | */ | ||
653 | omap->utmi_clk[i] = clk_get(dev, clkname); | ||
654 | if (IS_ERR(omap->utmi_clk[i])) | ||
655 | dev_dbg(dev, "Failed to get clock : %s : %ld\n", | ||
656 | clkname, PTR_ERR(omap->utmi_clk[i])); | ||
657 | |||
658 | snprintf(clkname, sizeof(clkname), | ||
659 | "usb_host_hs_hsic480m_p%d_clk", i + 1); | ||
660 | omap->hsic480m_clk[i] = clk_get(dev, clkname); | ||
661 | if (IS_ERR(omap->hsic480m_clk[i])) | ||
662 | dev_dbg(dev, "Failed to get clock : %s : %ld\n", | ||
663 | clkname, PTR_ERR(omap->hsic480m_clk[i])); | ||
664 | |||
665 | snprintf(clkname, sizeof(clkname), | ||
666 | "usb_host_hs_hsic60m_p%d_clk", i + 1); | ||
667 | omap->hsic60m_clk[i] = clk_get(dev, clkname); | ||
668 | if (IS_ERR(omap->hsic60m_clk[i])) | ||
669 | dev_dbg(dev, "Failed to get clock : %s : %ld\n", | ||
670 | clkname, PTR_ERR(omap->hsic60m_clk[i])); | ||
561 | } | 671 | } |
562 | 672 | ||
563 | if (is_ehci_phy_mode(pdata->port_mode[0])) { | 673 | if (is_ehci_phy_mode(pdata->port_mode[0])) { |
564 | /* for OMAP3 , the clk set paretn fails */ | 674 | /* for OMAP3, clk_set_parent fails */ |
565 | ret = clk_set_parent(omap->utmi_p1_fck, | 675 | ret = clk_set_parent(omap->utmi_p1_gfclk, |
566 | omap->xclk60mhsp1_ck); | 676 | omap->xclk60mhsp1_ck); |
567 | if (ret != 0) | 677 | if (ret != 0) |
568 | dev_err(dev, "xclk60mhsp1_ck set parent" | 678 | dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n", |
569 | "failed error:%d\n", ret); | 679 | ret); |
570 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { | 680 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { |
571 | ret = clk_set_parent(omap->utmi_p1_fck, | 681 | ret = clk_set_parent(omap->utmi_p1_gfclk, |
572 | omap->init_60m_fclk); | 682 | omap->init_60m_fclk); |
573 | if (ret != 0) | 683 | if (ret != 0) |
574 | dev_err(dev, "init_60m_fclk set parent" | 684 | dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n", |
575 | "failed error:%d\n", ret); | 685 | ret); |
576 | } | 686 | } |
577 | 687 | ||
578 | if (is_ehci_phy_mode(pdata->port_mode[1])) { | 688 | if (is_ehci_phy_mode(pdata->port_mode[1])) { |
579 | ret = clk_set_parent(omap->utmi_p2_fck, | 689 | ret = clk_set_parent(omap->utmi_p2_gfclk, |
580 | omap->xclk60mhsp2_ck); | 690 | omap->xclk60mhsp2_ck); |
581 | if (ret != 0) | 691 | if (ret != 0) |
582 | dev_err(dev, "xclk60mhsp2_ck set parent" | 692 | dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n", |
583 | "failed error:%d\n", ret); | 693 | ret); |
584 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { | 694 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { |
585 | ret = clk_set_parent(omap->utmi_p2_fck, | 695 | ret = clk_set_parent(omap->utmi_p2_gfclk, |
586 | omap->init_60m_fclk); | 696 | omap->init_60m_fclk); |
587 | if (ret != 0) | 697 | if (ret != 0) |
588 | dev_err(dev, "init_60m_fclk set parent" | 698 | dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n", |
589 | "failed error:%d\n", ret); | 699 | ret); |
590 | } | ||
591 | |||
592 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | ||
593 | if (!res) { | ||
594 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
595 | ret = -ENODEV; | ||
596 | goto err_init_60m_fclk; | ||
597 | } | ||
598 | |||
599 | omap->uhh_base = ioremap(res->start, resource_size(res)); | ||
600 | if (!omap->uhh_base) { | ||
601 | dev_err(dev, "UHH ioremap failed\n"); | ||
602 | ret = -ENOMEM; | ||
603 | goto err_init_60m_fclk; | ||
604 | } | 700 | } |
605 | 701 | ||
606 | platform_set_drvdata(pdev, omap); | ||
607 | |||
608 | omap_usbhs_init(dev); | 702 | omap_usbhs_init(dev); |
609 | ret = omap_usbhs_alloc_children(pdev); | 703 | ret = omap_usbhs_alloc_children(pdev); |
610 | if (ret) { | 704 | if (ret) { |
@@ -612,39 +706,41 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
612 | goto err_alloc; | 706 | goto err_alloc; |
613 | } | 707 | } |
614 | 708 | ||
615 | goto end_probe; | 709 | return 0; |
616 | 710 | ||
617 | err_alloc: | 711 | err_alloc: |
618 | omap_usbhs_deinit(&pdev->dev); | 712 | omap_usbhs_deinit(&pdev->dev); |
619 | iounmap(omap->uhh_base); | ||
620 | |||
621 | err_init_60m_fclk: | ||
622 | clk_put(omap->init_60m_fclk); | ||
623 | 713 | ||
624 | err_usbhost_p2_fck: | 714 | for (i = 0; i < omap->nports; i++) { |
625 | clk_put(omap->usbhost_p2_fck); | 715 | if (!IS_ERR(omap->utmi_clk[i])) |
716 | clk_put(omap->utmi_clk[i]); | ||
717 | if (!IS_ERR(omap->hsic60m_clk[i])) | ||
718 | clk_put(omap->hsic60m_clk[i]); | ||
719 | if (!IS_ERR(omap->hsic480m_clk[i])) | ||
720 | clk_put(omap->hsic480m_clk[i]); | ||
721 | } | ||
626 | 722 | ||
627 | err_usbhost_p1_fck: | 723 | clk_put(omap->init_60m_fclk); |
628 | clk_put(omap->usbhost_p1_fck); | ||
629 | 724 | ||
630 | err_xclk60mhsp2_ck: | 725 | err_init60m: |
631 | clk_put(omap->xclk60mhsp2_ck); | 726 | clk_put(omap->xclk60mhsp2_ck); |
632 | 727 | ||
633 | err_utmi_p2_fck: | 728 | err_xclk60mhsp2: |
634 | clk_put(omap->utmi_p2_fck); | ||
635 | |||
636 | err_xclk60mhsp1_ck: | ||
637 | clk_put(omap->xclk60mhsp1_ck); | 729 | clk_put(omap->xclk60mhsp1_ck); |
638 | 730 | ||
639 | err_utmi_p1_fck: | 731 | err_xclk60mhsp1: |
640 | clk_put(omap->utmi_p1_fck); | 732 | clk_put(omap->utmi_p2_gfclk); |
641 | 733 | ||
642 | err_end: | 734 | err_p2_gfclk: |
643 | clk_put(omap->ehci_logic_fck); | 735 | clk_put(omap->utmi_p1_gfclk); |
736 | |||
737 | err_p1_gfclk: | ||
738 | if (!IS_ERR(omap->ehci_logic_fck)) | ||
739 | clk_put(omap->ehci_logic_fck); | ||
740 | |||
741 | err_mem: | ||
644 | pm_runtime_disable(dev); | 742 | pm_runtime_disable(dev); |
645 | kfree(omap); | ||
646 | 743 | ||
647 | end_probe: | ||
648 | return ret; | 744 | return ret; |
649 | } | 745 | } |
650 | 746 | ||
@@ -657,19 +753,29 @@ end_probe: | |||
657 | static int usbhs_omap_remove(struct platform_device *pdev) | 753 | static int usbhs_omap_remove(struct platform_device *pdev) |
658 | { | 754 | { |
659 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | 755 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); |
756 | int i; | ||
660 | 757 | ||
661 | omap_usbhs_deinit(&pdev->dev); | 758 | omap_usbhs_deinit(&pdev->dev); |
662 | iounmap(omap->uhh_base); | 759 | |
760 | for (i = 0; i < omap->nports; i++) { | ||
761 | if (!IS_ERR(omap->utmi_clk[i])) | ||
762 | clk_put(omap->utmi_clk[i]); | ||
763 | if (!IS_ERR(omap->hsic60m_clk[i])) | ||
764 | clk_put(omap->hsic60m_clk[i]); | ||
765 | if (!IS_ERR(omap->hsic480m_clk[i])) | ||
766 | clk_put(omap->hsic480m_clk[i]); | ||
767 | } | ||
768 | |||
663 | clk_put(omap->init_60m_fclk); | 769 | clk_put(omap->init_60m_fclk); |
664 | clk_put(omap->usbhost_p2_fck); | 770 | clk_put(omap->utmi_p1_gfclk); |
665 | clk_put(omap->usbhost_p1_fck); | 771 | clk_put(omap->utmi_p2_gfclk); |
666 | clk_put(omap->xclk60mhsp2_ck); | 772 | clk_put(omap->xclk60mhsp2_ck); |
667 | clk_put(omap->utmi_p2_fck); | ||
668 | clk_put(omap->xclk60mhsp1_ck); | 773 | clk_put(omap->xclk60mhsp1_ck); |
669 | clk_put(omap->utmi_p1_fck); | 774 | |
670 | clk_put(omap->ehci_logic_fck); | 775 | if (!IS_ERR(omap->ehci_logic_fck)) |
776 | clk_put(omap->ehci_logic_fck); | ||
777 | |||
671 | pm_runtime_disable(&pdev->dev); | 778 | pm_runtime_disable(&pdev->dev); |
672 | kfree(omap); | ||
673 | 779 | ||
674 | return 0; | 780 | return 0; |
675 | } | 781 | } |
@@ -685,7 +791,7 @@ static struct platform_driver usbhs_omap_driver = { | |||
685 | .owner = THIS_MODULE, | 791 | .owner = THIS_MODULE, |
686 | .pm = &usbhsomap_dev_pm_ops, | 792 | .pm = &usbhsomap_dev_pm_ops, |
687 | }, | 793 | }, |
688 | .remove = __exit_p(usbhs_omap_remove), | 794 | .remove = usbhs_omap_remove, |
689 | }; | 795 | }; |
690 | 796 | ||
691 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | 797 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); |
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index eb869153206d..0aef1a768880 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c | |||
@@ -54,10 +54,13 @@ | |||
54 | 54 | ||
55 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | 55 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) |
56 | #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 | 56 | #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 |
57 | #define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16) | ||
58 | #define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15) | ||
57 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | 59 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) |
58 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | 60 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) |
59 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | 61 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) |
60 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | 62 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) |
63 | #define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI (2 << 1) | ||
61 | #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) | 64 | #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) |
62 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | 65 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) |
63 | 66 | ||
@@ -92,21 +95,25 @@ | |||
92 | #define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ | 95 | #define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ |
93 | #define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ | 96 | #define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ |
94 | #define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ | 97 | #define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ |
98 | #define OMAP_USBTLL_REV4 0x00000006 /* OMAP5 */ | ||
95 | 99 | ||
96 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) | 100 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) |
97 | 101 | ||
102 | /* only PHY and UNUSED modes don't need TLL */ | ||
103 | #define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\ | ||
104 | (x) != OMAP_EHCI_PORT_MODE_PHY) | ||
105 | |||
98 | struct usbtll_omap { | 106 | struct usbtll_omap { |
99 | struct clk *usbtll_p1_fck; | 107 | int nch; /* num. of channels */ |
100 | struct clk *usbtll_p2_fck; | 108 | struct usbhs_omap_platform_data *pdata; |
101 | struct usbtll_omap_platform_data platdata; | 109 | struct clk **ch_clk; |
102 | /* secure the register updates */ | ||
103 | spinlock_t lock; | ||
104 | }; | 110 | }; |
105 | 111 | ||
106 | /*-------------------------------------------------------------------------*/ | 112 | /*-------------------------------------------------------------------------*/ |
107 | 113 | ||
108 | const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; | 114 | static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; |
109 | struct platform_device *tll_pdev; | 115 | static struct device *tll_dev; |
116 | static DEFINE_SPINLOCK(tll_lock); /* serialize access to tll_dev */ | ||
110 | 117 | ||
111 | /*-------------------------------------------------------------------------*/ | 118 | /*-------------------------------------------------------------------------*/ |
112 | 119 | ||
@@ -203,84 +210,84 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | |||
203 | static int usbtll_omap_probe(struct platform_device *pdev) | 210 | static int usbtll_omap_probe(struct platform_device *pdev) |
204 | { | 211 | { |
205 | struct device *dev = &pdev->dev; | 212 | struct device *dev = &pdev->dev; |
206 | struct usbtll_omap_platform_data *pdata = dev->platform_data; | 213 | struct usbhs_omap_platform_data *pdata = dev->platform_data; |
207 | void __iomem *base; | 214 | void __iomem *base; |
208 | struct resource *res; | 215 | struct resource *res; |
209 | struct usbtll_omap *tll; | 216 | struct usbtll_omap *tll; |
210 | unsigned reg; | 217 | unsigned reg; |
211 | unsigned long flags; | ||
212 | int ret = 0; | 218 | int ret = 0; |
213 | int i, ver, count; | 219 | int i, ver; |
220 | bool needs_tll; | ||
214 | 221 | ||
215 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); | 222 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); |
216 | 223 | ||
217 | tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL); | 224 | tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL); |
218 | if (!tll) { | 225 | if (!tll) { |
219 | dev_err(dev, "Memory allocation failed\n"); | 226 | dev_err(dev, "Memory allocation failed\n"); |
220 | ret = -ENOMEM; | 227 | return -ENOMEM; |
221 | goto end; | ||
222 | } | 228 | } |
223 | 229 | ||
224 | spin_lock_init(&tll->lock); | 230 | if (!pdata) { |
225 | 231 | dev_err(dev, "Platform data missing\n"); | |
226 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | 232 | return -ENODEV; |
227 | tll->platdata.port_mode[i] = pdata->port_mode[i]; | ||
228 | |||
229 | tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
230 | if (IS_ERR(tll->usbtll_p1_fck)) { | ||
231 | ret = PTR_ERR(tll->usbtll_p1_fck); | ||
232 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
233 | goto err_tll; | ||
234 | } | 233 | } |
235 | 234 | ||
236 | tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | 235 | tll->pdata = pdata; |
237 | if (IS_ERR(tll->usbtll_p2_fck)) { | ||
238 | ret = PTR_ERR(tll->usbtll_p2_fck); | ||
239 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
240 | goto err_usbtll_p1_fck; | ||
241 | } | ||
242 | 236 | ||
243 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 237 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
244 | if (!res) { | 238 | base = devm_request_and_ioremap(dev, res); |
245 | dev_err(dev, "usb tll get resource failed\n"); | ||
246 | ret = -ENODEV; | ||
247 | goto err_usbtll_p2_fck; | ||
248 | } | ||
249 | |||
250 | base = ioremap(res->start, resource_size(res)); | ||
251 | if (!base) { | 239 | if (!base) { |
252 | dev_err(dev, "TLL ioremap failed\n"); | 240 | ret = -EADDRNOTAVAIL; |
253 | ret = -ENOMEM; | 241 | dev_err(dev, "Resource request/ioremap failed:%d\n", ret); |
254 | goto err_usbtll_p2_fck; | 242 | return ret; |
255 | } | 243 | } |
256 | 244 | ||
257 | platform_set_drvdata(pdev, tll); | 245 | platform_set_drvdata(pdev, tll); |
258 | pm_runtime_enable(dev); | 246 | pm_runtime_enable(dev); |
259 | pm_runtime_get_sync(dev); | 247 | pm_runtime_get_sync(dev); |
260 | 248 | ||
261 | spin_lock_irqsave(&tll->lock, flags); | ||
262 | |||
263 | ver = usbtll_read(base, OMAP_USBTLL_REVISION); | 249 | ver = usbtll_read(base, OMAP_USBTLL_REVISION); |
264 | switch (ver) { | 250 | switch (ver) { |
265 | case OMAP_USBTLL_REV1: | 251 | case OMAP_USBTLL_REV1: |
266 | case OMAP_USBTLL_REV2: | 252 | case OMAP_USBTLL_REV4: |
267 | count = OMAP_TLL_CHANNEL_COUNT; | 253 | tll->nch = OMAP_TLL_CHANNEL_COUNT; |
268 | break; | 254 | break; |
255 | case OMAP_USBTLL_REV2: | ||
269 | case OMAP_USBTLL_REV3: | 256 | case OMAP_USBTLL_REV3: |
270 | count = OMAP_REV2_TLL_CHANNEL_COUNT; | 257 | tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT; |
271 | break; | 258 | break; |
272 | default: | 259 | default: |
273 | dev_err(dev, "TLL version failed\n"); | 260 | tll->nch = OMAP_TLL_CHANNEL_COUNT; |
274 | ret = -ENODEV; | 261 | dev_dbg(dev, |
275 | goto err_ioremap; | 262 | "USB TLL Rev : 0x%x not recognized, assuming %d channels\n", |
263 | ver, tll->nch); | ||
264 | break; | ||
276 | } | 265 | } |
277 | 266 | ||
278 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | 267 | tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]), |
279 | is_ehci_tll_mode(pdata->port_mode[1]) || | 268 | GFP_KERNEL); |
280 | is_ehci_tll_mode(pdata->port_mode[2]) || | 269 | if (!tll->ch_clk) { |
281 | is_ohci_port(pdata->port_mode[0]) || | 270 | ret = -ENOMEM; |
282 | is_ohci_port(pdata->port_mode[1]) || | 271 | dev_err(dev, "Couldn't allocate memory for channel clocks\n"); |
283 | is_ohci_port(pdata->port_mode[2])) { | 272 | goto err_clk_alloc; |
273 | } | ||
274 | |||
275 | for (i = 0; i < tll->nch; i++) { | ||
276 | char clkname[] = "usb_tll_hs_usb_chx_clk"; | ||
277 | |||
278 | snprintf(clkname, sizeof(clkname), | ||
279 | "usb_tll_hs_usb_ch%d_clk", i); | ||
280 | tll->ch_clk[i] = clk_get(dev, clkname); | ||
281 | |||
282 | if (IS_ERR(tll->ch_clk[i])) | ||
283 | dev_dbg(dev, "can't get clock : %s\n", clkname); | ||
284 | } | ||
285 | |||
286 | needs_tll = false; | ||
287 | for (i = 0; i < tll->nch; i++) | ||
288 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); | ||
289 | |||
290 | if (needs_tll) { | ||
284 | 291 | ||
285 | /* Program Common TLL register */ | 292 | /* Program Common TLL register */ |
286 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); | 293 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); |
@@ -292,7 +299,7 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
292 | usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); | 299 | usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); |
293 | 300 | ||
294 | /* Enable channels now */ | 301 | /* Enable channels now */ |
295 | for (i = 0; i < count; i++) { | 302 | for (i = 0; i < tll->nch; i++) { |
296 | reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); | 303 | reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); |
297 | 304 | ||
298 | if (is_ohci_port(pdata->port_mode[i])) { | 305 | if (is_ohci_port(pdata->port_mode[i])) { |
@@ -308,6 +315,15 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
308 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | 315 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE |
309 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | 316 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF |
310 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | 317 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); |
318 | } else if (pdata->port_mode[i] == | ||
319 | OMAP_EHCI_PORT_MODE_HSIC) { | ||
320 | /* | ||
321 | * HSIC Mode requires UTMI port configurations | ||
322 | */ | ||
323 | reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS | ||
324 | | OMAP_TLL_CHANNEL_CONF_CHRGVBUS | ||
325 | | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI | ||
326 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF; | ||
311 | } else { | 327 | } else { |
312 | continue; | 328 | continue; |
313 | } | 329 | } |
@@ -320,25 +336,18 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
320 | } | 336 | } |
321 | } | 337 | } |
322 | 338 | ||
323 | err_ioremap: | ||
324 | spin_unlock_irqrestore(&tll->lock, flags); | ||
325 | iounmap(base); | ||
326 | pm_runtime_put_sync(dev); | 339 | pm_runtime_put_sync(dev); |
327 | tll_pdev = pdev; | 340 | /* only after this can omap_tll_enable/disable work */ |
328 | if (!ret) | 341 | spin_lock(&tll_lock); |
329 | goto end; | 342 | tll_dev = dev; |
330 | pm_runtime_disable(dev); | 343 | spin_unlock(&tll_lock); |
331 | 344 | ||
332 | err_usbtll_p2_fck: | 345 | return 0; |
333 | clk_put(tll->usbtll_p2_fck); | ||
334 | |||
335 | err_usbtll_p1_fck: | ||
336 | clk_put(tll->usbtll_p1_fck); | ||
337 | 346 | ||
338 | err_tll: | 347 | err_clk_alloc: |
339 | kfree(tll); | 348 | pm_runtime_put_sync(dev); |
349 | pm_runtime_disable(dev); | ||
340 | 350 | ||
341 | end: | ||
342 | return ret; | 351 | return ret; |
343 | } | 352 | } |
344 | 353 | ||
@@ -351,36 +360,42 @@ end: | |||
351 | static int usbtll_omap_remove(struct platform_device *pdev) | 360 | static int usbtll_omap_remove(struct platform_device *pdev) |
352 | { | 361 | { |
353 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | 362 | struct usbtll_omap *tll = platform_get_drvdata(pdev); |
363 | int i; | ||
364 | |||
365 | spin_lock(&tll_lock); | ||
366 | tll_dev = NULL; | ||
367 | spin_unlock(&tll_lock); | ||
368 | |||
369 | for (i = 0; i < tll->nch; i++) | ||
370 | if (!IS_ERR(tll->ch_clk[i])) | ||
371 | clk_put(tll->ch_clk[i]); | ||
354 | 372 | ||
355 | clk_put(tll->usbtll_p2_fck); | ||
356 | clk_put(tll->usbtll_p1_fck); | ||
357 | pm_runtime_disable(&pdev->dev); | 373 | pm_runtime_disable(&pdev->dev); |
358 | kfree(tll); | ||
359 | return 0; | 374 | return 0; |
360 | } | 375 | } |
361 | 376 | ||
362 | static int usbtll_runtime_resume(struct device *dev) | 377 | static int usbtll_runtime_resume(struct device *dev) |
363 | { | 378 | { |
364 | struct usbtll_omap *tll = dev_get_drvdata(dev); | 379 | struct usbtll_omap *tll = dev_get_drvdata(dev); |
365 | struct usbtll_omap_platform_data *pdata = &tll->platdata; | 380 | struct usbhs_omap_platform_data *pdata = tll->pdata; |
366 | unsigned long flags; | 381 | int i; |
367 | 382 | ||
368 | dev_dbg(dev, "usbtll_runtime_resume\n"); | 383 | dev_dbg(dev, "usbtll_runtime_resume\n"); |
369 | 384 | ||
370 | if (!pdata) { | 385 | for (i = 0; i < tll->nch; i++) { |
371 | dev_dbg(dev, "missing platform_data\n"); | 386 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
372 | return -ENODEV; | 387 | int r; |
373 | } | ||
374 | |||
375 | spin_lock_irqsave(&tll->lock, flags); | ||
376 | 388 | ||
377 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 389 | if (IS_ERR(tll->ch_clk[i])) |
378 | clk_enable(tll->usbtll_p1_fck); | 390 | continue; |
379 | |||
380 | if (is_ehci_tll_mode(pdata->port_mode[1])) | ||
381 | clk_enable(tll->usbtll_p2_fck); | ||
382 | 391 | ||
383 | spin_unlock_irqrestore(&tll->lock, flags); | 392 | r = clk_enable(tll->ch_clk[i]); |
393 | if (r) { | ||
394 | dev_err(dev, | ||
395 | "Error enabling ch %d clock: %d\n", i, r); | ||
396 | } | ||
397 | } | ||
398 | } | ||
384 | 399 | ||
385 | return 0; | 400 | return 0; |
386 | } | 401 | } |
@@ -388,26 +403,18 @@ static int usbtll_runtime_resume(struct device *dev) | |||
388 | static int usbtll_runtime_suspend(struct device *dev) | 403 | static int usbtll_runtime_suspend(struct device *dev) |
389 | { | 404 | { |
390 | struct usbtll_omap *tll = dev_get_drvdata(dev); | 405 | struct usbtll_omap *tll = dev_get_drvdata(dev); |
391 | struct usbtll_omap_platform_data *pdata = &tll->platdata; | 406 | struct usbhs_omap_platform_data *pdata = tll->pdata; |
392 | unsigned long flags; | 407 | int i; |
393 | 408 | ||
394 | dev_dbg(dev, "usbtll_runtime_suspend\n"); | 409 | dev_dbg(dev, "usbtll_runtime_suspend\n"); |
395 | 410 | ||
396 | if (!pdata) { | 411 | for (i = 0; i < tll->nch; i++) { |
397 | dev_dbg(dev, "missing platform_data\n"); | 412 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
398 | return -ENODEV; | 413 | if (!IS_ERR(tll->ch_clk[i])) |
414 | clk_disable(tll->ch_clk[i]); | ||
415 | } | ||
399 | } | 416 | } |
400 | 417 | ||
401 | spin_lock_irqsave(&tll->lock, flags); | ||
402 | |||
403 | if (is_ehci_tll_mode(pdata->port_mode[0])) | ||
404 | clk_disable(tll->usbtll_p1_fck); | ||
405 | |||
406 | if (is_ehci_tll_mode(pdata->port_mode[1])) | ||
407 | clk_disable(tll->usbtll_p2_fck); | ||
408 | |||
409 | spin_unlock_irqrestore(&tll->lock, flags); | ||
410 | |||
411 | return 0; | 418 | return 0; |
412 | } | 419 | } |
413 | 420 | ||
@@ -429,21 +436,39 @@ static struct platform_driver usbtll_omap_driver = { | |||
429 | 436 | ||
430 | int omap_tll_enable(void) | 437 | int omap_tll_enable(void) |
431 | { | 438 | { |
432 | if (!tll_pdev) { | 439 | int ret; |
433 | pr_err("missing omap usbhs tll platform_data\n"); | 440 | |
434 | return -ENODEV; | 441 | spin_lock(&tll_lock); |
442 | |||
443 | if (!tll_dev) { | ||
444 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
445 | ret = -ENODEV; | ||
446 | } else { | ||
447 | ret = pm_runtime_get_sync(tll_dev); | ||
435 | } | 448 | } |
436 | return pm_runtime_get_sync(&tll_pdev->dev); | 449 | |
450 | spin_unlock(&tll_lock); | ||
451 | |||
452 | return ret; | ||
437 | } | 453 | } |
438 | EXPORT_SYMBOL_GPL(omap_tll_enable); | 454 | EXPORT_SYMBOL_GPL(omap_tll_enable); |
439 | 455 | ||
440 | int omap_tll_disable(void) | 456 | int omap_tll_disable(void) |
441 | { | 457 | { |
442 | if (!tll_pdev) { | 458 | int ret; |
443 | pr_err("missing omap usbhs tll platform_data\n"); | 459 | |
444 | return -ENODEV; | 460 | spin_lock(&tll_lock); |
461 | |||
462 | if (!tll_dev) { | ||
463 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
464 | ret = -ENODEV; | ||
465 | } else { | ||
466 | ret = pm_runtime_put_sync(tll_dev); | ||
445 | } | 467 | } |
446 | return pm_runtime_put_sync(&tll_pdev->dev); | 468 | |
469 | spin_unlock(&tll_lock); | ||
470 | |||
471 | return ret; | ||
447 | } | 472 | } |
448 | EXPORT_SYMBOL_GPL(omap_tll_disable); | 473 | EXPORT_SYMBOL_GPL(omap_tll_disable); |
449 | 474 | ||
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index ac17a7c3a0cd..5d954d7b290d 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c | |||
@@ -107,7 +107,7 @@ static int omap_ehci_init(struct usb_hcd *hcd) | |||
107 | { | 107 | { |
108 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 108 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
109 | int rc; | 109 | int rc; |
110 | struct ehci_hcd_omap_platform_data *pdata; | 110 | struct usbhs_omap_platform_data *pdata; |
111 | 111 | ||
112 | pdata = hcd->self.controller->platform_data; | 112 | pdata = hcd->self.controller->platform_data; |
113 | 113 | ||
@@ -151,7 +151,7 @@ static int omap_ehci_init(struct usb_hcd *hcd) | |||
151 | } | 151 | } |
152 | 152 | ||
153 | static void disable_put_regulator( | 153 | static void disable_put_regulator( |
154 | struct ehci_hcd_omap_platform_data *pdata) | 154 | struct usbhs_omap_platform_data *pdata) |
155 | { | 155 | { |
156 | int i; | 156 | int i; |
157 | 157 | ||
@@ -176,7 +176,7 @@ static void disable_put_regulator( | |||
176 | static int ehci_hcd_omap_probe(struct platform_device *pdev) | 176 | static int ehci_hcd_omap_probe(struct platform_device *pdev) |
177 | { | 177 | { |
178 | struct device *dev = &pdev->dev; | 178 | struct device *dev = &pdev->dev; |
179 | struct ehci_hcd_omap_platform_data *pdata = dev->platform_data; | 179 | struct usbhs_omap_platform_data *pdata = dev->platform_data; |
180 | struct resource *res; | 180 | struct resource *res; |
181 | struct usb_hcd *hcd; | 181 | struct usb_hcd *hcd; |
182 | void __iomem *regs; | 182 | void __iomem *regs; |
diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index e697c85ad3bc..fa579b4c666b 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h | |||
@@ -55,6 +55,7 @@ struct ohci_hcd_omap_platform_data { | |||
55 | }; | 55 | }; |
56 | 56 | ||
57 | struct usbhs_omap_platform_data { | 57 | struct usbhs_omap_platform_data { |
58 | int nports; | ||
58 | enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; | 59 | enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; |
59 | int reset_gpio_port[OMAP3_HS_USB_PORTS]; | 60 | int reset_gpio_port[OMAP3_HS_USB_PORTS]; |
60 | struct regulator *regulator[OMAP3_HS_USB_PORTS]; | 61 | struct regulator *regulator[OMAP3_HS_USB_PORTS]; |