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