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