1 /* 2 * Copyright 2012 Freescale Semiconductor, Inc. 3 * Copyright (C) 2012 Marek Vasut <marex@denx.de> 4 * on behalf of DENX Software Engineering GmbH 5 * 6 * The code contained herein is licensed under the GNU General Public 7 * License. You may obtain a copy of the GNU General Public License 8 * Version 2 or later at the following locations: 9 * 10 * http://www.opensource.org/licenses/gpl-license.html 11 * http://www.gnu.org/copyleft/gpl.html 12 */ 13 14 #include <linux/module.h> 15 #include <linux/of_platform.h> 16 #include <linux/of_gpio.h> 17 #include <linux/platform_device.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/dma-mapping.h> 20 #include <linux/usb/chipidea.h> 21 #include <linux/usb/of.h> 22 #include <linux/clk.h> 23 24 #include "ci.h" 25 #include "ci_hdrc_imx.h" 26 27 struct ci_hdrc_imx_platform_flag { 28 unsigned int flags; 29 bool runtime_pm; 30 }; 31 32 static const struct ci_hdrc_imx_platform_flag imx23_usb_data = { 33 .flags = CI_HDRC_TURN_VBUS_EARLY_ON | 34 CI_HDRC_DISABLE_STREAMING, 35 }; 36 37 static const struct ci_hdrc_imx_platform_flag imx27_usb_data = { 38 CI_HDRC_DISABLE_STREAMING, 39 }; 40 41 static const struct ci_hdrc_imx_platform_flag imx28_usb_data = { 42 .flags = CI_HDRC_IMX28_WRITE_FIX | 43 CI_HDRC_TURN_VBUS_EARLY_ON | 44 CI_HDRC_DISABLE_STREAMING, 45 }; 46 47 static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = { 48 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 49 CI_HDRC_TURN_VBUS_EARLY_ON | 50 CI_HDRC_DISABLE_STREAMING, 51 }; 52 53 static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = { 54 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 55 CI_HDRC_TURN_VBUS_EARLY_ON | 56 CI_HDRC_DISABLE_HOST_STREAMING, 57 }; 58 59 static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = { 60 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 61 CI_HDRC_TURN_VBUS_EARLY_ON | 62 CI_HDRC_DISABLE_HOST_STREAMING, 63 }; 64 65 static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = { 66 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 67 CI_HDRC_TURN_VBUS_EARLY_ON, 68 }; 69 70 static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = { 71 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, 72 }; 73 74 static const struct of_device_id ci_hdrc_imx_dt_ids[] = { 75 { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data}, 76 { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, 77 { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, 78 { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data}, 79 { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data}, 80 { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data}, 81 { .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data}, 82 { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, 83 { /* sentinel */ } 84 }; 85 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); 86 87 struct ci_hdrc_imx_data { 88 struct usb_phy *phy; 89 struct platform_device *ci_pdev; 90 struct clk *clk; 91 struct imx_usbmisc_data *usbmisc_data; 92 bool supports_runtime_pm; 93 bool in_lpm; 94 /* SoC before i.mx6 (except imx23/imx28) needs three clks */ 95 bool need_three_clks; 96 struct clk *clk_ipg; 97 struct clk *clk_ahb; 98 struct clk *clk_per; 99 /* --------------------------------- */ 100 }; 101 102 /* Common functions shared by usbmisc drivers */ 103 104 static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) 105 { 106 struct platform_device *misc_pdev; 107 struct device_node *np = dev->of_node; 108 struct of_phandle_args args; 109 struct imx_usbmisc_data *data; 110 int ret; 111 112 /* 113 * In case the fsl,usbmisc property is not present this device doesn't 114 * need usbmisc. Return NULL (which is no error here) 115 */ 116 if (!of_get_property(np, "fsl,usbmisc", NULL)) 117 return NULL; 118 119 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 120 if (!data) 121 return ERR_PTR(-ENOMEM); 122 123 ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", 124 0, &args); 125 if (ret) { 126 dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", 127 ret); 128 return ERR_PTR(ret); 129 } 130 131 data->index = args.args[0]; 132 133 misc_pdev = of_find_device_by_node(args.np); 134 of_node_put(args.np); 135 136 if (!misc_pdev || !platform_get_drvdata(misc_pdev)) 137 return ERR_PTR(-EPROBE_DEFER); 138 139 data->dev = &misc_pdev->dev; 140 141 if (of_find_property(np, "disable-over-current", NULL)) 142 data->disable_oc = 1; 143 144 if (of_find_property(np, "over-current-active-high", NULL)) 145 data->oc_polarity = 1; 146 147 if (of_find_property(np, "external-vbus-divider", NULL)) 148 data->evdo = 1; 149 150 if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) 151 data->ulpi = 1; 152 153 return data; 154 } 155 156 /* End of common functions shared by usbmisc drivers*/ 157 static int imx_get_clks(struct device *dev) 158 { 159 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 160 int ret = 0; 161 162 data->clk_ipg = devm_clk_get(dev, "ipg"); 163 if (IS_ERR(data->clk_ipg)) { 164 /* If the platform only needs one clocks */ 165 data->clk = devm_clk_get(dev, NULL); 166 if (IS_ERR(data->clk)) { 167 ret = PTR_ERR(data->clk); 168 dev_err(dev, 169 "Failed to get clks, err=%ld,%ld\n", 170 PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); 171 return ret; 172 } 173 return ret; 174 } 175 176 data->clk_ahb = devm_clk_get(dev, "ahb"); 177 if (IS_ERR(data->clk_ahb)) { 178 ret = PTR_ERR(data->clk_ahb); 179 dev_err(dev, 180 "Failed to get ahb clock, err=%d\n", ret); 181 return ret; 182 } 183 184 data->clk_per = devm_clk_get(dev, "per"); 185 if (IS_ERR(data->clk_per)) { 186 ret = PTR_ERR(data->clk_per); 187 dev_err(dev, 188 "Failed to get per clock, err=%d\n", ret); 189 return ret; 190 } 191 192 data->need_three_clks = true; 193 return ret; 194 } 195 196 static int imx_prepare_enable_clks(struct device *dev) 197 { 198 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 199 int ret = 0; 200 201 if (data->need_three_clks) { 202 ret = clk_prepare_enable(data->clk_ipg); 203 if (ret) { 204 dev_err(dev, 205 "Failed to prepare/enable ipg clk, err=%d\n", 206 ret); 207 return ret; 208 } 209 210 ret = clk_prepare_enable(data->clk_ahb); 211 if (ret) { 212 dev_err(dev, 213 "Failed to prepare/enable ahb clk, err=%d\n", 214 ret); 215 clk_disable_unprepare(data->clk_ipg); 216 return ret; 217 } 218 219 ret = clk_prepare_enable(data->clk_per); 220 if (ret) { 221 dev_err(dev, 222 "Failed to prepare/enable per clk, err=%d\n", 223 ret); 224 clk_disable_unprepare(data->clk_ahb); 225 clk_disable_unprepare(data->clk_ipg); 226 return ret; 227 } 228 } else { 229 ret = clk_prepare_enable(data->clk); 230 if (ret) { 231 dev_err(dev, 232 "Failed to prepare/enable clk, err=%d\n", 233 ret); 234 return ret; 235 } 236 } 237 238 return ret; 239 } 240 241 static void imx_disable_unprepare_clks(struct device *dev) 242 { 243 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 244 245 if (data->need_three_clks) { 246 clk_disable_unprepare(data->clk_per); 247 clk_disable_unprepare(data->clk_ahb); 248 clk_disable_unprepare(data->clk_ipg); 249 } else { 250 clk_disable_unprepare(data->clk); 251 } 252 } 253 254 static int ci_hdrc_imx_probe(struct platform_device *pdev) 255 { 256 struct ci_hdrc_imx_data *data; 257 struct ci_hdrc_platform_data pdata = { 258 .name = dev_name(&pdev->dev), 259 .capoffset = DEF_CAPOFFSET, 260 }; 261 int ret; 262 const struct of_device_id *of_id; 263 const struct ci_hdrc_imx_platform_flag *imx_platform_flag; 264 265 of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); 266 if (!of_id) 267 return -ENODEV; 268 269 imx_platform_flag = of_id->data; 270 271 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 272 if (!data) 273 return -ENOMEM; 274 275 platform_set_drvdata(pdev, data); 276 data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); 277 if (IS_ERR(data->usbmisc_data)) 278 return PTR_ERR(data->usbmisc_data); 279 280 ret = imx_get_clks(&pdev->dev); 281 if (ret) 282 return ret; 283 284 ret = imx_prepare_enable_clks(&pdev->dev); 285 if (ret) 286 return ret; 287 288 data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); 289 if (IS_ERR(data->phy)) { 290 ret = PTR_ERR(data->phy); 291 /* Return -EINVAL if no usbphy is available */ 292 if (ret == -ENODEV) 293 ret = -EINVAL; 294 goto err_clk; 295 } 296 297 pdata.usb_phy = data->phy; 298 pdata.flags |= imx_platform_flag->flags; 299 if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) 300 data->supports_runtime_pm = true; 301 302 ret = imx_usbmisc_init(data->usbmisc_data); 303 if (ret) { 304 dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); 305 goto err_clk; 306 } 307 308 data->ci_pdev = ci_hdrc_add_device(&pdev->dev, 309 pdev->resource, pdev->num_resources, 310 &pdata); 311 if (IS_ERR(data->ci_pdev)) { 312 ret = PTR_ERR(data->ci_pdev); 313 if (ret != -EPROBE_DEFER) 314 dev_err(&pdev->dev, 315 "ci_hdrc_add_device failed, err=%d\n", ret); 316 goto err_clk; 317 } 318 319 ret = imx_usbmisc_init_post(data->usbmisc_data); 320 if (ret) { 321 dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret); 322 goto disable_device; 323 } 324 325 if (data->supports_runtime_pm) { 326 pm_runtime_set_active(&pdev->dev); 327 pm_runtime_enable(&pdev->dev); 328 } 329 330 device_set_wakeup_capable(&pdev->dev, true); 331 332 return 0; 333 334 disable_device: 335 ci_hdrc_remove_device(data->ci_pdev); 336 err_clk: 337 imx_disable_unprepare_clks(&pdev->dev); 338 return ret; 339 } 340 341 static int ci_hdrc_imx_remove(struct platform_device *pdev) 342 { 343 struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev); 344 345 if (data->supports_runtime_pm) { 346 pm_runtime_get_sync(&pdev->dev); 347 pm_runtime_disable(&pdev->dev); 348 pm_runtime_put_noidle(&pdev->dev); 349 } 350 ci_hdrc_remove_device(data->ci_pdev); 351 imx_disable_unprepare_clks(&pdev->dev); 352 353 return 0; 354 } 355 356 static void ci_hdrc_imx_shutdown(struct platform_device *pdev) 357 { 358 ci_hdrc_imx_remove(pdev); 359 } 360 361 #ifdef CONFIG_PM 362 static int imx_controller_suspend(struct device *dev) 363 { 364 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 365 366 dev_dbg(dev, "at %s\n", __func__); 367 368 imx_disable_unprepare_clks(dev); 369 data->in_lpm = true; 370 371 return 0; 372 } 373 374 static int imx_controller_resume(struct device *dev) 375 { 376 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 377 int ret = 0; 378 379 dev_dbg(dev, "at %s\n", __func__); 380 381 if (!data->in_lpm) { 382 WARN_ON(1); 383 return 0; 384 } 385 386 ret = imx_prepare_enable_clks(dev); 387 if (ret) 388 return ret; 389 390 data->in_lpm = false; 391 392 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false); 393 if (ret) { 394 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret); 395 goto clk_disable; 396 } 397 398 return 0; 399 400 clk_disable: 401 imx_disable_unprepare_clks(dev); 402 return ret; 403 } 404 405 #ifdef CONFIG_PM_SLEEP 406 static int ci_hdrc_imx_suspend(struct device *dev) 407 { 408 int ret; 409 410 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 411 412 if (data->in_lpm) 413 /* The core's suspend doesn't run */ 414 return 0; 415 416 if (device_may_wakeup(dev)) { 417 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true); 418 if (ret) { 419 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", 420 ret); 421 return ret; 422 } 423 } 424 425 return imx_controller_suspend(dev); 426 } 427 428 static int ci_hdrc_imx_resume(struct device *dev) 429 { 430 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 431 int ret; 432 433 ret = imx_controller_resume(dev); 434 if (!ret && data->supports_runtime_pm) { 435 pm_runtime_disable(dev); 436 pm_runtime_set_active(dev); 437 pm_runtime_enable(dev); 438 } 439 440 return ret; 441 } 442 #endif /* CONFIG_PM_SLEEP */ 443 444 static int ci_hdrc_imx_runtime_suspend(struct device *dev) 445 { 446 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 447 int ret; 448 449 if (data->in_lpm) { 450 WARN_ON(1); 451 return 0; 452 } 453 454 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true); 455 if (ret) { 456 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret); 457 return ret; 458 } 459 460 return imx_controller_suspend(dev); 461 } 462 463 static int ci_hdrc_imx_runtime_resume(struct device *dev) 464 { 465 return imx_controller_resume(dev); 466 } 467 468 #endif /* CONFIG_PM */ 469 470 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { 471 SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) 472 SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, 473 ci_hdrc_imx_runtime_resume, NULL) 474 }; 475 static struct platform_driver ci_hdrc_imx_driver = { 476 .probe = ci_hdrc_imx_probe, 477 .remove = ci_hdrc_imx_remove, 478 .shutdown = ci_hdrc_imx_shutdown, 479 .driver = { 480 .name = "imx_usb", 481 .of_match_table = ci_hdrc_imx_dt_ids, 482 .pm = &ci_hdrc_imx_pm_ops, 483 }, 484 }; 485 486 module_platform_driver(ci_hdrc_imx_driver); 487 488 MODULE_ALIAS("platform:imx-usb"); 489 MODULE_LICENSE("GPL v2"); 490 MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); 491 MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 492 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); 493