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