linux/drivers/usb/dwc3/dwc3-of-simple.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * dwc3-of-simple.c - OF glue layer for simple integrations
   4 *
   5 * Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com
   6 *
   7 * Author: Felipe Balbi <balbi@ti.com>
   8 *
   9 * This is a combination of the old dwc3-qcom.c by Ivan T. Ivanov
  10 * <iivanov@mm-sol.com> and the original patch adding support for Xilinx' SoC
  11 * by Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com>
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/kernel.h>
  16#include <linux/slab.h>
  17#include <linux/platform_device.h>
  18#include <linux/dma-mapping.h>
  19#include <linux/clk.h>
  20#include <linux/of.h>
  21#include <linux/of_platform.h>
  22#include <linux/pm_runtime.h>
  23#include <linux/reset.h>
  24
  25struct dwc3_of_simple {
  26        struct device           *dev;
  27        struct clk_bulk_data    *clks;
  28        int                     num_clocks;
  29        struct reset_control    *resets;
  30        bool                    need_reset;
  31};
  32
  33static int dwc3_of_simple_probe(struct platform_device *pdev)
  34{
  35        struct dwc3_of_simple   *simple;
  36        struct device           *dev = &pdev->dev;
  37        struct device_node      *np = dev->of_node;
  38
  39        int                     ret;
  40
  41        simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
  42        if (!simple)
  43                return -ENOMEM;
  44
  45        platform_set_drvdata(pdev, simple);
  46        simple->dev = dev;
  47
  48        /*
  49         * Some controllers need to toggle the usb3-otg reset before trying to
  50         * initialize the PHY, otherwise the PHY times out.
  51         */
  52        if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
  53                simple->need_reset = true;
  54
  55        simple->resets = of_reset_control_array_get(np, false, true,
  56                                                    true);
  57        if (IS_ERR(simple->resets)) {
  58                ret = PTR_ERR(simple->resets);
  59                dev_err(dev, "failed to get device resets, err=%d\n", ret);
  60                return ret;
  61        }
  62
  63        ret = reset_control_deassert(simple->resets);
  64        if (ret)
  65                goto err_resetc_put;
  66
  67        ret = clk_bulk_get_all(simple->dev, &simple->clks);
  68        if (ret < 0)
  69                goto err_resetc_assert;
  70
  71        simple->num_clocks = ret;
  72        ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks);
  73        if (ret)
  74                goto err_resetc_assert;
  75
  76        ret = of_platform_populate(np, NULL, NULL, dev);
  77        if (ret)
  78                goto err_clk_put;
  79
  80        pm_runtime_set_active(dev);
  81        pm_runtime_enable(dev);
  82        pm_runtime_get_sync(dev);
  83
  84        return 0;
  85
  86err_clk_put:
  87        clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
  88        clk_bulk_put_all(simple->num_clocks, simple->clks);
  89
  90err_resetc_assert:
  91        reset_control_assert(simple->resets);
  92
  93err_resetc_put:
  94        reset_control_put(simple->resets);
  95        return ret;
  96}
  97
  98static void __dwc3_of_simple_teardown(struct dwc3_of_simple *simple)
  99{
 100        of_platform_depopulate(simple->dev);
 101
 102        clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
 103        clk_bulk_put_all(simple->num_clocks, simple->clks);
 104        simple->num_clocks = 0;
 105
 106        reset_control_assert(simple->resets);
 107
 108        reset_control_put(simple->resets);
 109
 110        pm_runtime_disable(simple->dev);
 111        pm_runtime_put_noidle(simple->dev);
 112        pm_runtime_set_suspended(simple->dev);
 113}
 114
 115static int dwc3_of_simple_remove(struct platform_device *pdev)
 116{
 117        struct dwc3_of_simple   *simple = platform_get_drvdata(pdev);
 118
 119        __dwc3_of_simple_teardown(simple);
 120
 121        return 0;
 122}
 123
 124static void dwc3_of_simple_shutdown(struct platform_device *pdev)
 125{
 126        struct dwc3_of_simple   *simple = platform_get_drvdata(pdev);
 127
 128        __dwc3_of_simple_teardown(simple);
 129}
 130
 131static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev)
 132{
 133        struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
 134
 135        clk_bulk_disable(simple->num_clocks, simple->clks);
 136
 137        return 0;
 138}
 139
 140static int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev)
 141{
 142        struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
 143
 144        return clk_bulk_enable(simple->num_clocks, simple->clks);
 145}
 146
 147static int __maybe_unused dwc3_of_simple_suspend(struct device *dev)
 148{
 149        struct dwc3_of_simple *simple = dev_get_drvdata(dev);
 150
 151        if (simple->need_reset)
 152                reset_control_assert(simple->resets);
 153
 154        return 0;
 155}
 156
 157static int __maybe_unused dwc3_of_simple_resume(struct device *dev)
 158{
 159        struct dwc3_of_simple *simple = dev_get_drvdata(dev);
 160
 161        if (simple->need_reset)
 162                reset_control_deassert(simple->resets);
 163
 164        return 0;
 165}
 166
 167static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
 168        SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume)
 169        SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
 170                        dwc3_of_simple_runtime_resume, NULL)
 171};
 172
 173static const struct of_device_id of_dwc3_simple_match[] = {
 174        { .compatible = "rockchip,rk3399-dwc3" },
 175        { .compatible = "cavium,octeon-7130-usb-uctl" },
 176        { .compatible = "sprd,sc9860-dwc3" },
 177        { .compatible = "allwinner,sun50i-h6-dwc3" },
 178        { .compatible = "hisilicon,hi3670-dwc3" },
 179        { .compatible = "intel,keembay-dwc3" },
 180        { /* Sentinel */ }
 181};
 182MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
 183
 184static struct platform_driver dwc3_of_simple_driver = {
 185        .probe          = dwc3_of_simple_probe,
 186        .remove         = dwc3_of_simple_remove,
 187        .shutdown       = dwc3_of_simple_shutdown,
 188        .driver         = {
 189                .name   = "dwc3-of-simple",
 190                .of_match_table = of_dwc3_simple_match,
 191                .pm     = &dwc3_of_simple_dev_pm_ops,
 192        },
 193};
 194
 195module_platform_driver(dwc3_of_simple_driver);
 196MODULE_LICENSE("GPL v2");
 197MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
 198MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 199