| .. | .. |
|---|
| 7 | 7 | |
|---|
| 8 | 8 | #include <linux/module.h> |
|---|
| 9 | 9 | #include <linux/of_platform.h> |
|---|
| 10 | | -#include <linux/of_gpio.h> |
|---|
| 11 | 10 | #include <linux/platform_device.h> |
|---|
| 12 | 11 | #include <linux/pm_runtime.h> |
|---|
| 13 | | -#include <linux/dma-mapping.h> |
|---|
| 14 | 12 | #include <linux/usb/chipidea.h> |
|---|
| 15 | 13 | #include <linux/usb/of.h> |
|---|
| 16 | 14 | #include <linux/clk.h> |
|---|
| 15 | +#include <linux/pinctrl/consumer.h> |
|---|
| 16 | +#include <linux/pm_qos.h> |
|---|
| 17 | 17 | |
|---|
| 18 | 18 | #include "ci.h" |
|---|
| 19 | 19 | #include "ci_hdrc_imx.h" |
|---|
| .. | .. |
|---|
| 65 | 65 | .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, |
|---|
| 66 | 66 | }; |
|---|
| 67 | 67 | |
|---|
| 68 | +static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = { |
|---|
| 69 | + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | |
|---|
| 70 | + CI_HDRC_PMQOS, |
|---|
| 71 | +}; |
|---|
| 72 | + |
|---|
| 73 | +static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { |
|---|
| 74 | + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, |
|---|
| 75 | +}; |
|---|
| 76 | + |
|---|
| 68 | 77 | static const struct of_device_id ci_hdrc_imx_dt_ids[] = { |
|---|
| 69 | 78 | { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data}, |
|---|
| 70 | 79 | { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, |
|---|
| .. | .. |
|---|
| 74 | 83 | { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data}, |
|---|
| 75 | 84 | { .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data}, |
|---|
| 76 | 85 | { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, |
|---|
| 86 | + { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data}, |
|---|
| 87 | + { .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data}, |
|---|
| 77 | 88 | { /* sentinel */ } |
|---|
| 78 | 89 | }; |
|---|
| 79 | 90 | MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); |
|---|
| .. | .. |
|---|
| 86 | 97 | bool supports_runtime_pm; |
|---|
| 87 | 98 | bool override_phy_control; |
|---|
| 88 | 99 | bool in_lpm; |
|---|
| 100 | + struct pinctrl *pinctrl; |
|---|
| 101 | + struct pinctrl_state *pinctrl_hsic_active; |
|---|
| 102 | + struct regulator *hsic_pad_regulator; |
|---|
| 89 | 103 | /* SoC before i.mx6 (except imx23/imx28) needs three clks */ |
|---|
| 90 | 104 | bool need_three_clks; |
|---|
| 91 | 105 | struct clk *clk_ipg; |
|---|
| 92 | 106 | struct clk *clk_ahb; |
|---|
| 93 | 107 | struct clk *clk_per; |
|---|
| 94 | 108 | /* --------------------------------- */ |
|---|
| 109 | + struct pm_qos_request pm_qos_req; |
|---|
| 110 | + const struct ci_hdrc_imx_platform_flag *plat_data; |
|---|
| 95 | 111 | }; |
|---|
| 96 | 112 | |
|---|
| 97 | 113 | /* Common functions shared by usbmisc drivers */ |
|---|
| .. | .. |
|---|
| 137 | 153 | } |
|---|
| 138 | 154 | data->dev = &misc_pdev->dev; |
|---|
| 139 | 155 | |
|---|
| 140 | | - if (of_find_property(np, "disable-over-current", NULL)) |
|---|
| 156 | + /* |
|---|
| 157 | + * Check the various over current related properties. If over current |
|---|
| 158 | + * detection is disabled we're not interested in the polarity. |
|---|
| 159 | + */ |
|---|
| 160 | + if (of_find_property(np, "disable-over-current", NULL)) { |
|---|
| 141 | 161 | data->disable_oc = 1; |
|---|
| 162 | + } else if (of_find_property(np, "over-current-active-high", NULL)) { |
|---|
| 163 | + data->oc_pol_active_low = 0; |
|---|
| 164 | + data->oc_pol_configured = 1; |
|---|
| 165 | + } else if (of_find_property(np, "over-current-active-low", NULL)) { |
|---|
| 166 | + data->oc_pol_active_low = 1; |
|---|
| 167 | + data->oc_pol_configured = 1; |
|---|
| 168 | + } else { |
|---|
| 169 | + dev_warn(dev, "No over current polarity defined\n"); |
|---|
| 170 | + } |
|---|
| 142 | 171 | |
|---|
| 143 | | - if (of_find_property(np, "over-current-active-high", NULL)) |
|---|
| 144 | | - data->oc_polarity = 1; |
|---|
| 145 | | - |
|---|
| 146 | | - if (of_find_property(np, "external-vbus-divider", NULL)) |
|---|
| 147 | | - data->evdo = 1; |
|---|
| 172 | + data->pwr_pol = of_property_read_bool(np, "power-active-high"); |
|---|
| 173 | + data->evdo = of_property_read_bool(np, "external-vbus-divider"); |
|---|
| 148 | 174 | |
|---|
| 149 | 175 | if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) |
|---|
| 150 | 176 | data->ulpi = 1; |
|---|
| 177 | + |
|---|
| 178 | + if (of_property_read_u32(np, "samsung,picophy-pre-emp-curr-control", |
|---|
| 179 | + &data->emp_curr_control)) |
|---|
| 180 | + data->emp_curr_control = -1; |
|---|
| 181 | + if (of_property_read_u32(np, "samsung,picophy-dc-vol-level-adjust", |
|---|
| 182 | + &data->dc_vol_level_adjust)) |
|---|
| 183 | + data->dc_vol_level_adjust = -1; |
|---|
| 151 | 184 | |
|---|
| 152 | 185 | return data; |
|---|
| 153 | 186 | } |
|---|
| .. | .. |
|---|
| 250 | 283 | } |
|---|
| 251 | 284 | } |
|---|
| 252 | 285 | |
|---|
| 286 | +static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) |
|---|
| 287 | +{ |
|---|
| 288 | + struct device *dev = ci->dev->parent; |
|---|
| 289 | + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
|---|
| 290 | + int ret = 0; |
|---|
| 291 | + struct imx_usbmisc_data *mdata = data->usbmisc_data; |
|---|
| 292 | + |
|---|
| 293 | + switch (event) { |
|---|
| 294 | + case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: |
|---|
| 295 | + if (data->pinctrl) { |
|---|
| 296 | + ret = pinctrl_select_state(data->pinctrl, |
|---|
| 297 | + data->pinctrl_hsic_active); |
|---|
| 298 | + if (ret) |
|---|
| 299 | + dev_err(dev, |
|---|
| 300 | + "hsic_active select failed, err=%d\n", |
|---|
| 301 | + ret); |
|---|
| 302 | + } |
|---|
| 303 | + break; |
|---|
| 304 | + case CI_HDRC_IMX_HSIC_SUSPEND_EVENT: |
|---|
| 305 | + ret = imx_usbmisc_hsic_set_connect(mdata); |
|---|
| 306 | + if (ret) |
|---|
| 307 | + dev_err(dev, |
|---|
| 308 | + "hsic_set_connect failed, err=%d\n", ret); |
|---|
| 309 | + break; |
|---|
| 310 | + case CI_HDRC_CONTROLLER_VBUS_EVENT: |
|---|
| 311 | + if (ci->vbus_active) |
|---|
| 312 | + ret = imx_usbmisc_charger_detection(mdata, true); |
|---|
| 313 | + else |
|---|
| 314 | + ret = imx_usbmisc_charger_detection(mdata, false); |
|---|
| 315 | + if (ci->usb_phy) |
|---|
| 316 | + schedule_work(&ci->usb_phy->chg_work); |
|---|
| 317 | + break; |
|---|
| 318 | + default: |
|---|
| 319 | + break; |
|---|
| 320 | + } |
|---|
| 321 | + |
|---|
| 322 | + return ret; |
|---|
| 323 | +} |
|---|
| 324 | + |
|---|
| 253 | 325 | static int ci_hdrc_imx_probe(struct platform_device *pdev) |
|---|
| 254 | 326 | { |
|---|
| 255 | 327 | struct ci_hdrc_imx_data *data; |
|---|
| 256 | 328 | struct ci_hdrc_platform_data pdata = { |
|---|
| 257 | 329 | .name = dev_name(&pdev->dev), |
|---|
| 258 | 330 | .capoffset = DEF_CAPOFFSET, |
|---|
| 331 | + .notify_event = ci_hdrc_imx_notify_event, |
|---|
| 259 | 332 | }; |
|---|
| 260 | 333 | int ret; |
|---|
| 261 | 334 | const struct of_device_id *of_id; |
|---|
| 262 | 335 | const struct ci_hdrc_imx_platform_flag *imx_platform_flag; |
|---|
| 263 | 336 | struct device_node *np = pdev->dev.of_node; |
|---|
| 337 | + struct device *dev = &pdev->dev; |
|---|
| 264 | 338 | |
|---|
| 265 | | - of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); |
|---|
| 339 | + of_id = of_match_device(ci_hdrc_imx_dt_ids, dev); |
|---|
| 266 | 340 | if (!of_id) |
|---|
| 267 | 341 | return -ENODEV; |
|---|
| 268 | 342 | |
|---|
| .. | .. |
|---|
| 272 | 346 | if (!data) |
|---|
| 273 | 347 | return -ENOMEM; |
|---|
| 274 | 348 | |
|---|
| 349 | + data->plat_data = imx_platform_flag; |
|---|
| 350 | + pdata.flags |= imx_platform_flag->flags; |
|---|
| 275 | 351 | platform_set_drvdata(pdev, data); |
|---|
| 276 | | - data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); |
|---|
| 352 | + data->usbmisc_data = usbmisc_get_init_data(dev); |
|---|
| 277 | 353 | if (IS_ERR(data->usbmisc_data)) |
|---|
| 278 | 354 | return PTR_ERR(data->usbmisc_data); |
|---|
| 279 | 355 | |
|---|
| 280 | | - ret = imx_get_clks(&pdev->dev); |
|---|
| 281 | | - if (ret) |
|---|
| 282 | | - return ret; |
|---|
| 356 | + if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) |
|---|
| 357 | + && data->usbmisc_data) { |
|---|
| 358 | + pdata.flags |= CI_HDRC_IMX_IS_HSIC; |
|---|
| 359 | + data->usbmisc_data->hsic = 1; |
|---|
| 360 | + data->pinctrl = devm_pinctrl_get(dev); |
|---|
| 361 | + if (PTR_ERR(data->pinctrl) == -ENODEV) |
|---|
| 362 | + data->pinctrl = NULL; |
|---|
| 363 | + else if (IS_ERR(data->pinctrl)) { |
|---|
| 364 | + if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER) |
|---|
| 365 | + dev_err(dev, "pinctrl get failed, err=%ld\n", |
|---|
| 366 | + PTR_ERR(data->pinctrl)); |
|---|
| 367 | + return PTR_ERR(data->pinctrl); |
|---|
| 368 | + } |
|---|
| 283 | 369 | |
|---|
| 284 | | - ret = imx_prepare_enable_clks(&pdev->dev); |
|---|
| 285 | | - if (ret) |
|---|
| 286 | | - return ret; |
|---|
| 370 | + data->hsic_pad_regulator = |
|---|
| 371 | + devm_regulator_get_optional(dev, "hsic"); |
|---|
| 372 | + if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { |
|---|
| 373 | + /* no pad regualator is needed */ |
|---|
| 374 | + data->hsic_pad_regulator = NULL; |
|---|
| 375 | + } else if (IS_ERR(data->hsic_pad_regulator)) { |
|---|
| 376 | + if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER) |
|---|
| 377 | + dev_err(dev, |
|---|
| 378 | + "Get HSIC pad regulator error: %ld\n", |
|---|
| 379 | + PTR_ERR(data->hsic_pad_regulator)); |
|---|
| 380 | + return PTR_ERR(data->hsic_pad_regulator); |
|---|
| 381 | + } |
|---|
| 287 | 382 | |
|---|
| 288 | | - data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); |
|---|
| 383 | + if (data->hsic_pad_regulator) { |
|---|
| 384 | + ret = regulator_enable(data->hsic_pad_regulator); |
|---|
| 385 | + if (ret) { |
|---|
| 386 | + dev_err(dev, |
|---|
| 387 | + "Failed to enable HSIC pad regulator\n"); |
|---|
| 388 | + return ret; |
|---|
| 389 | + } |
|---|
| 390 | + } |
|---|
| 391 | + } |
|---|
| 392 | + |
|---|
| 393 | + /* HSIC pinctrl handling */ |
|---|
| 394 | + if (data->pinctrl) { |
|---|
| 395 | + struct pinctrl_state *pinctrl_hsic_idle; |
|---|
| 396 | + |
|---|
| 397 | + pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); |
|---|
| 398 | + if (IS_ERR(pinctrl_hsic_idle)) { |
|---|
| 399 | + dev_err(dev, |
|---|
| 400 | + "pinctrl_hsic_idle lookup failed, err=%ld\n", |
|---|
| 401 | + PTR_ERR(pinctrl_hsic_idle)); |
|---|
| 402 | + return PTR_ERR(pinctrl_hsic_idle); |
|---|
| 403 | + } |
|---|
| 404 | + |
|---|
| 405 | + ret = pinctrl_select_state(data->pinctrl, pinctrl_hsic_idle); |
|---|
| 406 | + if (ret) { |
|---|
| 407 | + dev_err(dev, "hsic_idle select failed, err=%d\n", ret); |
|---|
| 408 | + return ret; |
|---|
| 409 | + } |
|---|
| 410 | + |
|---|
| 411 | + data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl, |
|---|
| 412 | + "active"); |
|---|
| 413 | + if (IS_ERR(data->pinctrl_hsic_active)) { |
|---|
| 414 | + dev_err(dev, |
|---|
| 415 | + "pinctrl_hsic_active lookup failed, err=%ld\n", |
|---|
| 416 | + PTR_ERR(data->pinctrl_hsic_active)); |
|---|
| 417 | + return PTR_ERR(data->pinctrl_hsic_active); |
|---|
| 418 | + } |
|---|
| 419 | + } |
|---|
| 420 | + |
|---|
| 421 | + if (pdata.flags & CI_HDRC_PMQOS) |
|---|
| 422 | + cpu_latency_qos_add_request(&data->pm_qos_req, 0); |
|---|
| 423 | + |
|---|
| 424 | + ret = imx_get_clks(dev); |
|---|
| 425 | + if (ret) |
|---|
| 426 | + goto disable_hsic_regulator; |
|---|
| 427 | + |
|---|
| 428 | + ret = imx_prepare_enable_clks(dev); |
|---|
| 429 | + if (ret) |
|---|
| 430 | + goto disable_hsic_regulator; |
|---|
| 431 | + |
|---|
| 432 | + data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); |
|---|
| 289 | 433 | if (IS_ERR(data->phy)) { |
|---|
| 290 | 434 | ret = PTR_ERR(data->phy); |
|---|
| 291 | | - /* Return -EINVAL if no usbphy is available */ |
|---|
| 292 | | - if (ret == -ENODEV) |
|---|
| 293 | | - ret = -EINVAL; |
|---|
| 294 | | - goto err_clk; |
|---|
| 435 | + if (ret != -ENODEV) |
|---|
| 436 | + goto err_clk; |
|---|
| 437 | + data->phy = devm_usb_get_phy_by_phandle(dev, "phys", 0); |
|---|
| 438 | + if (IS_ERR(data->phy)) { |
|---|
| 439 | + ret = PTR_ERR(data->phy); |
|---|
| 440 | + if (ret == -ENODEV) |
|---|
| 441 | + data->phy = NULL; |
|---|
| 442 | + else |
|---|
| 443 | + goto err_clk; |
|---|
| 444 | + } |
|---|
| 295 | 445 | } |
|---|
| 296 | 446 | |
|---|
| 297 | 447 | pdata.usb_phy = data->phy; |
|---|
| 448 | + if (data->usbmisc_data) |
|---|
| 449 | + data->usbmisc_data->usb_phy = data->phy; |
|---|
| 298 | 450 | |
|---|
| 299 | 451 | if ((of_device_is_compatible(np, "fsl,imx53-usb") || |
|---|
| 300 | 452 | of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy && |
|---|
| .. | .. |
|---|
| 304 | 456 | usb_phy_init(pdata.usb_phy); |
|---|
| 305 | 457 | } |
|---|
| 306 | 458 | |
|---|
| 307 | | - pdata.flags |= imx_platform_flag->flags; |
|---|
| 308 | 459 | if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) |
|---|
| 309 | 460 | data->supports_runtime_pm = true; |
|---|
| 310 | 461 | |
|---|
| 311 | 462 | ret = imx_usbmisc_init(data->usbmisc_data); |
|---|
| 312 | 463 | if (ret) { |
|---|
| 313 | | - dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); |
|---|
| 464 | + dev_err(dev, "usbmisc init failed, ret=%d\n", ret); |
|---|
| 314 | 465 | goto err_clk; |
|---|
| 315 | 466 | } |
|---|
| 316 | 467 | |
|---|
| 317 | | - data->ci_pdev = ci_hdrc_add_device(&pdev->dev, |
|---|
| 468 | + data->ci_pdev = ci_hdrc_add_device(dev, |
|---|
| 318 | 469 | pdev->resource, pdev->num_resources, |
|---|
| 319 | 470 | &pdata); |
|---|
| 320 | 471 | if (IS_ERR(data->ci_pdev)) { |
|---|
| 321 | 472 | ret = PTR_ERR(data->ci_pdev); |
|---|
| 322 | 473 | if (ret != -EPROBE_DEFER) |
|---|
| 323 | | - dev_err(&pdev->dev, |
|---|
| 324 | | - "ci_hdrc_add_device failed, err=%d\n", ret); |
|---|
| 474 | + dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", |
|---|
| 475 | + ret); |
|---|
| 325 | 476 | goto err_clk; |
|---|
| 477 | + } |
|---|
| 478 | + |
|---|
| 479 | + if (data->usbmisc_data) { |
|---|
| 480 | + if (!IS_ERR(pdata.id_extcon.edev) || |
|---|
| 481 | + of_property_read_bool(np, "usb-role-switch")) |
|---|
| 482 | + data->usbmisc_data->ext_id = 1; |
|---|
| 483 | + |
|---|
| 484 | + if (!IS_ERR(pdata.vbus_extcon.edev) || |
|---|
| 485 | + of_property_read_bool(np, "usb-role-switch")) |
|---|
| 486 | + data->usbmisc_data->ext_vbus = 1; |
|---|
| 487 | + |
|---|
| 488 | + /* usbmisc needs to know dr mode to choose wakeup setting */ |
|---|
| 489 | + data->usbmisc_data->available_role = |
|---|
| 490 | + ci_hdrc_query_available_role(data->ci_pdev); |
|---|
| 326 | 491 | } |
|---|
| 327 | 492 | |
|---|
| 328 | 493 | ret = imx_usbmisc_init_post(data->usbmisc_data); |
|---|
| 329 | 494 | if (ret) { |
|---|
| 330 | | - dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret); |
|---|
| 495 | + dev_err(dev, "usbmisc post failed, ret=%d\n", ret); |
|---|
| 331 | 496 | goto disable_device; |
|---|
| 332 | 497 | } |
|---|
| 333 | 498 | |
|---|
| 334 | 499 | if (data->supports_runtime_pm) { |
|---|
| 335 | | - pm_runtime_set_active(&pdev->dev); |
|---|
| 336 | | - pm_runtime_enable(&pdev->dev); |
|---|
| 500 | + pm_runtime_set_active(dev); |
|---|
| 501 | + pm_runtime_enable(dev); |
|---|
| 337 | 502 | } |
|---|
| 338 | 503 | |
|---|
| 339 | | - device_set_wakeup_capable(&pdev->dev, true); |
|---|
| 504 | + device_set_wakeup_capable(dev, true); |
|---|
| 340 | 505 | |
|---|
| 341 | 506 | return 0; |
|---|
| 342 | 507 | |
|---|
| 343 | 508 | disable_device: |
|---|
| 344 | 509 | ci_hdrc_remove_device(data->ci_pdev); |
|---|
| 345 | 510 | err_clk: |
|---|
| 346 | | - imx_disable_unprepare_clks(&pdev->dev); |
|---|
| 511 | + imx_disable_unprepare_clks(dev); |
|---|
| 512 | +disable_hsic_regulator: |
|---|
| 513 | + if (data->hsic_pad_regulator) |
|---|
| 514 | + /* don't overwrite original ret (cf. EPROBE_DEFER) */ |
|---|
| 515 | + regulator_disable(data->hsic_pad_regulator); |
|---|
| 516 | + if (pdata.flags & CI_HDRC_PMQOS) |
|---|
| 517 | + cpu_latency_qos_remove_request(&data->pm_qos_req); |
|---|
| 518 | + data->ci_pdev = NULL; |
|---|
| 347 | 519 | return ret; |
|---|
| 348 | 520 | } |
|---|
| 349 | 521 | |
|---|
| .. | .. |
|---|
| 356 | 528 | pm_runtime_disable(&pdev->dev); |
|---|
| 357 | 529 | pm_runtime_put_noidle(&pdev->dev); |
|---|
| 358 | 530 | } |
|---|
| 359 | | - ci_hdrc_remove_device(data->ci_pdev); |
|---|
| 531 | + if (data->ci_pdev) |
|---|
| 532 | + ci_hdrc_remove_device(data->ci_pdev); |
|---|
| 360 | 533 | if (data->override_phy_control) |
|---|
| 361 | 534 | usb_phy_shutdown(data->phy); |
|---|
| 362 | | - imx_disable_unprepare_clks(&pdev->dev); |
|---|
| 535 | + if (data->ci_pdev) { |
|---|
| 536 | + imx_disable_unprepare_clks(&pdev->dev); |
|---|
| 537 | + if (data->plat_data->flags & CI_HDRC_PMQOS) |
|---|
| 538 | + cpu_latency_qos_remove_request(&data->pm_qos_req); |
|---|
| 539 | + if (data->hsic_pad_regulator) |
|---|
| 540 | + regulator_disable(data->hsic_pad_regulator); |
|---|
| 541 | + } |
|---|
| 363 | 542 | |
|---|
| 364 | 543 | return 0; |
|---|
| 365 | 544 | } |
|---|
| .. | .. |
|---|
| 369 | 548 | ci_hdrc_imx_remove(pdev); |
|---|
| 370 | 549 | } |
|---|
| 371 | 550 | |
|---|
| 372 | | -#ifdef CONFIG_PM |
|---|
| 373 | | -static int imx_controller_suspend(struct device *dev) |
|---|
| 551 | +static int __maybe_unused imx_controller_suspend(struct device *dev) |
|---|
| 374 | 552 | { |
|---|
| 375 | 553 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
|---|
| 554 | + int ret = 0; |
|---|
| 376 | 555 | |
|---|
| 377 | 556 | dev_dbg(dev, "at %s\n", __func__); |
|---|
| 378 | 557 | |
|---|
| 558 | + ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false); |
|---|
| 559 | + if (ret) { |
|---|
| 560 | + dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); |
|---|
| 561 | + return ret; |
|---|
| 562 | + } |
|---|
| 563 | + |
|---|
| 379 | 564 | imx_disable_unprepare_clks(dev); |
|---|
| 565 | + if (data->plat_data->flags & CI_HDRC_PMQOS) |
|---|
| 566 | + cpu_latency_qos_remove_request(&data->pm_qos_req); |
|---|
| 567 | + |
|---|
| 380 | 568 | data->in_lpm = true; |
|---|
| 381 | 569 | |
|---|
| 382 | 570 | return 0; |
|---|
| 383 | 571 | } |
|---|
| 384 | 572 | |
|---|
| 385 | | -static int imx_controller_resume(struct device *dev) |
|---|
| 573 | +static int __maybe_unused imx_controller_resume(struct device *dev) |
|---|
| 386 | 574 | { |
|---|
| 387 | 575 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
|---|
| 388 | 576 | int ret = 0; |
|---|
| .. | .. |
|---|
| 393 | 581 | WARN_ON(1); |
|---|
| 394 | 582 | return 0; |
|---|
| 395 | 583 | } |
|---|
| 584 | + |
|---|
| 585 | + if (data->plat_data->flags & CI_HDRC_PMQOS) |
|---|
| 586 | + cpu_latency_qos_add_request(&data->pm_qos_req, 0); |
|---|
| 396 | 587 | |
|---|
| 397 | 588 | ret = imx_prepare_enable_clks(dev); |
|---|
| 398 | 589 | if (ret) |
|---|
| .. | .. |
|---|
| 406 | 597 | goto clk_disable; |
|---|
| 407 | 598 | } |
|---|
| 408 | 599 | |
|---|
| 600 | + ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true); |
|---|
| 601 | + if (ret) { |
|---|
| 602 | + dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); |
|---|
| 603 | + goto hsic_set_clk_fail; |
|---|
| 604 | + } |
|---|
| 605 | + |
|---|
| 409 | 606 | return 0; |
|---|
| 410 | 607 | |
|---|
| 608 | +hsic_set_clk_fail: |
|---|
| 609 | + imx_usbmisc_set_wakeup(data->usbmisc_data, true); |
|---|
| 411 | 610 | clk_disable: |
|---|
| 412 | 611 | imx_disable_unprepare_clks(dev); |
|---|
| 413 | 612 | return ret; |
|---|
| 414 | 613 | } |
|---|
| 415 | 614 | |
|---|
| 416 | | -#ifdef CONFIG_PM_SLEEP |
|---|
| 417 | | -static int ci_hdrc_imx_suspend(struct device *dev) |
|---|
| 615 | +static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev) |
|---|
| 418 | 616 | { |
|---|
| 419 | 617 | int ret; |
|---|
| 420 | 618 | |
|---|
| .. | .. |
|---|
| 433 | 631 | } |
|---|
| 434 | 632 | } |
|---|
| 435 | 633 | |
|---|
| 436 | | - return imx_controller_suspend(dev); |
|---|
| 634 | + ret = imx_controller_suspend(dev); |
|---|
| 635 | + if (ret) |
|---|
| 636 | + return ret; |
|---|
| 637 | + |
|---|
| 638 | + pinctrl_pm_select_sleep_state(dev); |
|---|
| 639 | + return ret; |
|---|
| 437 | 640 | } |
|---|
| 438 | 641 | |
|---|
| 439 | | -static int ci_hdrc_imx_resume(struct device *dev) |
|---|
| 642 | +static int __maybe_unused ci_hdrc_imx_resume(struct device *dev) |
|---|
| 440 | 643 | { |
|---|
| 441 | 644 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
|---|
| 442 | 645 | int ret; |
|---|
| 443 | 646 | |
|---|
| 647 | + pinctrl_pm_select_default_state(dev); |
|---|
| 444 | 648 | ret = imx_controller_resume(dev); |
|---|
| 445 | 649 | if (!ret && data->supports_runtime_pm) { |
|---|
| 446 | 650 | pm_runtime_disable(dev); |
|---|
| .. | .. |
|---|
| 450 | 654 | |
|---|
| 451 | 655 | return ret; |
|---|
| 452 | 656 | } |
|---|
| 453 | | -#endif /* CONFIG_PM_SLEEP */ |
|---|
| 454 | 657 | |
|---|
| 455 | | -static int ci_hdrc_imx_runtime_suspend(struct device *dev) |
|---|
| 658 | +static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev) |
|---|
| 456 | 659 | { |
|---|
| 457 | 660 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
|---|
| 458 | 661 | int ret; |
|---|
| .. | .. |
|---|
| 471 | 674 | return imx_controller_suspend(dev); |
|---|
| 472 | 675 | } |
|---|
| 473 | 676 | |
|---|
| 474 | | -static int ci_hdrc_imx_runtime_resume(struct device *dev) |
|---|
| 677 | +static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev) |
|---|
| 475 | 678 | { |
|---|
| 476 | 679 | return imx_controller_resume(dev); |
|---|
| 477 | 680 | } |
|---|
| 478 | | - |
|---|
| 479 | | -#endif /* CONFIG_PM */ |
|---|
| 480 | 681 | |
|---|
| 481 | 682 | static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { |
|---|
| 482 | 683 | SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) |
|---|
| .. | .. |
|---|
| 497 | 698 | module_platform_driver(ci_hdrc_imx_driver); |
|---|
| 498 | 699 | |
|---|
| 499 | 700 | MODULE_ALIAS("platform:imx-usb"); |
|---|
| 500 | | -MODULE_LICENSE("GPL v2"); |
|---|
| 701 | +MODULE_LICENSE("GPL"); |
|---|
| 501 | 702 | MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); |
|---|
| 502 | 703 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); |
|---|
| 503 | 704 | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); |
|---|