diff options
| -rw-r--r-- | drivers/usb/phy/phy-msm-usb.c | 140 | ||||
| -rw-r--r-- | include/linux/usb/msm_hsusb_hw.h | 5 |
2 files changed, 93 insertions, 52 deletions
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8d57045ac938..bb339963f8bb 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #define DRIVER_NAME "msm_otg" | 48 | #define DRIVER_NAME "msm_otg" |
| 49 | 49 | ||
| 50 | #define ULPI_IO_TIMEOUT_USEC (10 * 1000) | 50 | #define ULPI_IO_TIMEOUT_USEC (10 * 1000) |
| 51 | #define LINK_RESET_TIMEOUT_USEC (250 * 1000) | ||
| 51 | 52 | ||
| 52 | #define USB_PHY_3P3_VOL_MIN 3050000 /* uV */ | 53 | #define USB_PHY_3P3_VOL_MIN 3050000 /* uV */ |
| 53 | #define USB_PHY_3P3_VOL_MAX 3300000 /* uV */ | 54 | #define USB_PHY_3P3_VOL_MAX 3300000 /* uV */ |
| @@ -267,77 +268,35 @@ static int msm_otg_phy_clk_reset(struct msm_otg *motg) | |||
| 267 | return ret; | 268 | return ret; |
| 268 | } | 269 | } |
| 269 | 270 | ||
| 270 | static int msm_otg_phy_reset(struct msm_otg *motg) | 271 | static int msm_link_reset(struct msm_otg *motg) |
| 271 | { | 272 | { |
| 272 | u32 val; | 273 | u32 val; |
| 273 | int ret; | 274 | int ret; |
| 274 | int retries; | ||
| 275 | 275 | ||
| 276 | ret = msm_otg_link_clk_reset(motg, 1); | 276 | ret = msm_otg_link_clk_reset(motg, 1); |
| 277 | if (ret) | 277 | if (ret) |
| 278 | return ret; | 278 | return ret; |
| 279 | ret = msm_otg_phy_clk_reset(motg); | ||
| 280 | if (ret) | ||
| 281 | return ret; | ||
| 282 | ret = msm_otg_link_clk_reset(motg, 0); | ||
| 283 | if (ret) | ||
| 284 | return ret; | ||
| 285 | 279 | ||
| 286 | val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; | 280 | /* wait for 1ms delay as suggested in HPG. */ |
| 287 | writel(val | PORTSC_PTS_ULPI, USB_PORTSC); | 281 | usleep_range(1000, 1200); |
| 288 | |||
| 289 | for (retries = 3; retries > 0; retries--) { | ||
| 290 | ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM, | ||
| 291 | ULPI_CLR(ULPI_FUNC_CTRL)); | ||
| 292 | if (!ret) | ||
| 293 | break; | ||
| 294 | ret = msm_otg_phy_clk_reset(motg); | ||
| 295 | if (ret) | ||
| 296 | return ret; | ||
| 297 | } | ||
| 298 | if (!retries) | ||
| 299 | return -ETIMEDOUT; | ||
| 300 | 282 | ||
| 301 | /* This reset calibrates the phy, if the above write succeeded */ | 283 | ret = msm_otg_link_clk_reset(motg, 0); |
| 302 | ret = msm_otg_phy_clk_reset(motg); | ||
| 303 | if (ret) | 284 | if (ret) |
| 304 | return ret; | 285 | return ret; |
| 305 | 286 | ||
| 306 | for (retries = 3; retries > 0; retries--) { | ||
| 307 | ret = ulpi_read(&motg->phy, ULPI_DEBUG); | ||
| 308 | if (ret != -ETIMEDOUT) | ||
| 309 | break; | ||
| 310 | ret = msm_otg_phy_clk_reset(motg); | ||
| 311 | if (ret) | ||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | if (!retries) | ||
| 315 | return -ETIMEDOUT; | ||
| 316 | |||
| 317 | if (motg->phy_number) | 287 | if (motg->phy_number) |
| 318 | writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); | 288 | writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); |
| 319 | 289 | ||
| 320 | dev_info(motg->phy.dev, "phy_reset: success\n"); | 290 | val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; |
| 291 | writel(val | PORTSC_PTS_ULPI, USB_PORTSC); | ||
| 292 | |||
| 321 | return 0; | 293 | return 0; |
| 322 | } | 294 | } |
| 323 | 295 | ||
| 324 | #define LINK_RESET_TIMEOUT_USEC (250 * 1000) | ||
| 325 | static int msm_otg_reset(struct usb_phy *phy) | 296 | static int msm_otg_reset(struct usb_phy *phy) |
| 326 | { | 297 | { |
| 327 | struct msm_otg *motg = container_of(phy, struct msm_otg, phy); | 298 | struct msm_otg *motg = container_of(phy, struct msm_otg, phy); |
| 328 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
| 329 | int cnt = 0; | 299 | int cnt = 0; |
| 330 | int ret; | ||
| 331 | u32 val = 0; | ||
| 332 | u32 ulpi_val = 0; | ||
| 333 | |||
| 334 | ret = msm_otg_phy_reset(motg); | ||
| 335 | if (ret) { | ||
| 336 | dev_err(phy->dev, "phy_reset failed\n"); | ||
| 337 | return ret; | ||
| 338 | } | ||
| 339 | |||
| 340 | ulpi_init(motg); | ||
| 341 | 300 | ||
| 342 | writel(USBCMD_RESET, USB_USBCMD); | 301 | writel(USBCMD_RESET, USB_USBCMD); |
| 343 | while (cnt < LINK_RESET_TIMEOUT_USEC) { | 302 | while (cnt < LINK_RESET_TIMEOUT_USEC) { |
| @@ -351,11 +310,86 @@ static int msm_otg_reset(struct usb_phy *phy) | |||
| 351 | 310 | ||
| 352 | /* select ULPI phy */ | 311 | /* select ULPI phy */ |
| 353 | writel(0x80000000, USB_PORTSC); | 312 | writel(0x80000000, USB_PORTSC); |
| 313 | writel(0x0, USB_AHBBURST); | ||
| 314 | writel(0x08, USB_AHBMODE); | ||
| 315 | |||
| 316 | if (motg->phy_number) | ||
| 317 | writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); | ||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | static void msm_phy_reset(struct msm_otg *motg) | ||
| 322 | { | ||
| 323 | void __iomem *addr; | ||
| 324 | |||
| 325 | if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) { | ||
| 326 | msm_otg_phy_clk_reset(motg); | ||
| 327 | return; | ||
| 328 | } | ||
| 329 | |||
| 330 | addr = USB_PHY_CTRL; | ||
| 331 | if (motg->phy_number) | ||
| 332 | addr = USB_PHY_CTRL2; | ||
| 333 | |||
| 334 | /* Assert USB PHY_POR */ | ||
| 335 | writel(readl(addr) | PHY_POR_ASSERT, addr); | ||
| 336 | |||
| 337 | /* | ||
| 338 | * wait for minimum 10 microseconds as suggested in HPG. | ||
| 339 | * Use a slightly larger value since the exact value didn't | ||
| 340 | * work 100% of the time. | ||
| 341 | */ | ||
| 342 | udelay(12); | ||
| 343 | |||
| 344 | /* Deassert USB PHY_POR */ | ||
| 345 | writel(readl(addr) & ~PHY_POR_ASSERT, addr); | ||
| 346 | } | ||
| 347 | |||
| 348 | static int msm_usb_reset(struct usb_phy *phy) | ||
| 349 | { | ||
| 350 | struct msm_otg *motg = container_of(phy, struct msm_otg, phy); | ||
| 351 | int ret; | ||
| 352 | |||
| 353 | if (!IS_ERR(motg->core_clk)) | ||
| 354 | clk_prepare_enable(motg->core_clk); | ||
| 355 | |||
| 356 | ret = msm_link_reset(motg); | ||
| 357 | if (ret) { | ||
| 358 | dev_err(phy->dev, "phy_reset failed\n"); | ||
| 359 | return ret; | ||
| 360 | } | ||
| 361 | |||
| 362 | ret = msm_otg_reset(&motg->phy); | ||
| 363 | if (ret) { | ||
| 364 | dev_err(phy->dev, "link reset failed\n"); | ||
| 365 | return ret; | ||
| 366 | } | ||
| 354 | 367 | ||
| 355 | msleep(100); | 368 | msleep(100); |
| 356 | 369 | ||
| 357 | writel(0x0, USB_AHBBURST); | 370 | /* Reset USB PHY after performing USB Link RESET */ |
| 358 | writel(0x00, USB_AHBMODE); | 371 | msm_phy_reset(motg); |
| 372 | |||
| 373 | if (!IS_ERR(motg->core_clk)) | ||
| 374 | clk_disable_unprepare(motg->core_clk); | ||
| 375 | |||
| 376 | return 0; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int msm_phy_init(struct usb_phy *phy) | ||
| 380 | { | ||
| 381 | struct msm_otg *motg = container_of(phy, struct msm_otg, phy); | ||
| 382 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
| 383 | u32 val, ulpi_val = 0; | ||
| 384 | |||
| 385 | /* Program USB PHY Override registers. */ | ||
| 386 | ulpi_init(motg); | ||
| 387 | |||
| 388 | /* | ||
| 389 | * It is recommended in HPG to reset USB PHY after programming | ||
| 390 | * USB PHY Override registers. | ||
| 391 | */ | ||
| 392 | msm_phy_reset(motg); | ||
| 359 | 393 | ||
| 360 | if (pdata->otg_control == OTG_PHY_CONTROL) { | 394 | if (pdata->otg_control == OTG_PHY_CONTROL) { |
| 361 | val = readl(USB_OTGSC); | 395 | val = readl(USB_OTGSC); |
| @@ -1574,7 +1608,7 @@ static int msm_otg_probe(struct platform_device *pdev) | |||
| 1574 | goto disable_ldo; | 1608 | goto disable_ldo; |
| 1575 | } | 1609 | } |
| 1576 | 1610 | ||
| 1577 | phy->init = msm_otg_reset; | 1611 | phy->init = msm_phy_init; |
| 1578 | phy->set_power = msm_otg_set_power; | 1612 | phy->set_power = msm_otg_set_power; |
| 1579 | 1613 | ||
| 1580 | phy->io_ops = &msm_otg_io_ops; | 1614 | phy->io_ops = &msm_otg_io_ops; |
| @@ -1583,6 +1617,8 @@ static int msm_otg_probe(struct platform_device *pdev) | |||
| 1583 | phy->otg->set_host = msm_otg_set_host; | 1617 | phy->otg->set_host = msm_otg_set_host; |
| 1584 | phy->otg->set_peripheral = msm_otg_set_peripheral; | 1618 | phy->otg->set_peripheral = msm_otg_set_peripheral; |
| 1585 | 1619 | ||
| 1620 | msm_usb_reset(phy); | ||
| 1621 | |||
| 1586 | ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); | 1622 | ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); |
| 1587 | if (ret) { | 1623 | if (ret) { |
| 1588 | dev_err(&pdev->dev, "usb_add_phy failed\n"); | 1624 | dev_err(&pdev->dev, "usb_add_phy failed\n"); |
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index e6d703567155..575c74397e52 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h | |||
| @@ -42,9 +42,14 @@ | |||
| 42 | #define ULPI_DATA(n) ((n) & 255) | 42 | #define ULPI_DATA(n) ((n) & 255) |
| 43 | #define ULPI_DATA_READ(n) (((n) >> 8) & 255) | 43 | #define ULPI_DATA_READ(n) (((n) >> 8) & 255) |
| 44 | 44 | ||
| 45 | /* synopsys 28nm phy registers */ | ||
| 46 | #define ULPI_PWR_CLK_MNG_REG 0x88 | ||
| 47 | #define OTG_COMP_DISABLE BIT(0) | ||
| 48 | |||
| 45 | #define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */ | 49 | #define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */ |
| 46 | #define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */ | 50 | #define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */ |
| 47 | #define PHY_RETEN (1 << 1) /* PHY retention enable/disable */ | 51 | #define PHY_RETEN (1 << 1) /* PHY retention enable/disable */ |
| 52 | #define PHY_POR_ASSERT (1 << 0) /* USB2 28nm PHY POR ASSERT */ | ||
| 48 | 53 | ||
| 49 | /* OTG definitions */ | 54 | /* OTG definitions */ |
| 50 | #define OTGSC_INTSTS_MASK (0x7f << 16) | 55 | #define OTGSC_INTSTS_MASK (0x7f << 16) |
