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]; |
