Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * dwc3-of-simple.c - OF glue layer for simple integrations
0004  *
0005  * Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com
0006  *
0007  * Author: Felipe Balbi <balbi@ti.com>
0008  *
0009  * This is a combination of the old dwc3-qcom.c by Ivan T. Ivanov
0010  * <iivanov@mm-sol.com> and the original patch adding support for Xilinx' SoC
0011  * by Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com>
0012  */
0013 
0014 #include <linux/module.h>
0015 #include <linux/kernel.h>
0016 #include <linux/slab.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/dma-mapping.h>
0019 #include <linux/clk.h>
0020 #include <linux/of.h>
0021 #include <linux/of_platform.h>
0022 #include <linux/pm_runtime.h>
0023 #include <linux/reset.h>
0024 
0025 struct dwc3_of_simple {
0026     struct device       *dev;
0027     struct clk_bulk_data    *clks;
0028     int         num_clocks;
0029     struct reset_control    *resets;
0030     bool            need_reset;
0031 };
0032 
0033 static int dwc3_of_simple_probe(struct platform_device *pdev)
0034 {
0035     struct dwc3_of_simple   *simple;
0036     struct device       *dev = &pdev->dev;
0037     struct device_node  *np = dev->of_node;
0038 
0039     int         ret;
0040 
0041     simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
0042     if (!simple)
0043         return -ENOMEM;
0044 
0045     platform_set_drvdata(pdev, simple);
0046     simple->dev = dev;
0047 
0048     /*
0049      * Some controllers need to toggle the usb3-otg reset before trying to
0050      * initialize the PHY, otherwise the PHY times out.
0051      */
0052     if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
0053         simple->need_reset = true;
0054 
0055     simple->resets = of_reset_control_array_get(np, false, true,
0056                             true);
0057     if (IS_ERR(simple->resets)) {
0058         ret = PTR_ERR(simple->resets);
0059         dev_err(dev, "failed to get device resets, err=%d\n", ret);
0060         return ret;
0061     }
0062 
0063     ret = reset_control_deassert(simple->resets);
0064     if (ret)
0065         goto err_resetc_put;
0066 
0067     ret = clk_bulk_get_all(simple->dev, &simple->clks);
0068     if (ret < 0)
0069         goto err_resetc_assert;
0070 
0071     simple->num_clocks = ret;
0072     ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks);
0073     if (ret)
0074         goto err_resetc_assert;
0075 
0076     ret = of_platform_populate(np, NULL, NULL, dev);
0077     if (ret)
0078         goto err_clk_put;
0079 
0080     pm_runtime_set_active(dev);
0081     pm_runtime_enable(dev);
0082     pm_runtime_get_sync(dev);
0083 
0084     return 0;
0085 
0086 err_clk_put:
0087     clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
0088     clk_bulk_put_all(simple->num_clocks, simple->clks);
0089 
0090 err_resetc_assert:
0091     reset_control_assert(simple->resets);
0092 
0093 err_resetc_put:
0094     reset_control_put(simple->resets);
0095     return ret;
0096 }
0097 
0098 static void __dwc3_of_simple_teardown(struct dwc3_of_simple *simple)
0099 {
0100     of_platform_depopulate(simple->dev);
0101 
0102     clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
0103     clk_bulk_put_all(simple->num_clocks, simple->clks);
0104     simple->num_clocks = 0;
0105 
0106     reset_control_assert(simple->resets);
0107 
0108     reset_control_put(simple->resets);
0109 
0110     pm_runtime_disable(simple->dev);
0111     pm_runtime_put_noidle(simple->dev);
0112     pm_runtime_set_suspended(simple->dev);
0113 }
0114 
0115 static int dwc3_of_simple_remove(struct platform_device *pdev)
0116 {
0117     struct dwc3_of_simple   *simple = platform_get_drvdata(pdev);
0118 
0119     __dwc3_of_simple_teardown(simple);
0120 
0121     return 0;
0122 }
0123 
0124 static void dwc3_of_simple_shutdown(struct platform_device *pdev)
0125 {
0126     struct dwc3_of_simple   *simple = platform_get_drvdata(pdev);
0127 
0128     __dwc3_of_simple_teardown(simple);
0129 }
0130 
0131 static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev)
0132 {
0133     struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
0134 
0135     clk_bulk_disable(simple->num_clocks, simple->clks);
0136 
0137     return 0;
0138 }
0139 
0140 static int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev)
0141 {
0142     struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
0143 
0144     return clk_bulk_enable(simple->num_clocks, simple->clks);
0145 }
0146 
0147 static int __maybe_unused dwc3_of_simple_suspend(struct device *dev)
0148 {
0149     struct dwc3_of_simple *simple = dev_get_drvdata(dev);
0150 
0151     if (simple->need_reset)
0152         reset_control_assert(simple->resets);
0153 
0154     return 0;
0155 }
0156 
0157 static int __maybe_unused dwc3_of_simple_resume(struct device *dev)
0158 {
0159     struct dwc3_of_simple *simple = dev_get_drvdata(dev);
0160 
0161     if (simple->need_reset)
0162         reset_control_deassert(simple->resets);
0163 
0164     return 0;
0165 }
0166 
0167 static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
0168     SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume)
0169     SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
0170             dwc3_of_simple_runtime_resume, NULL)
0171 };
0172 
0173 static const struct of_device_id of_dwc3_simple_match[] = {
0174     { .compatible = "rockchip,rk3399-dwc3" },
0175     { .compatible = "cavium,octeon-7130-usb-uctl" },
0176     { .compatible = "sprd,sc9860-dwc3" },
0177     { .compatible = "allwinner,sun50i-h6-dwc3" },
0178     { .compatible = "hisilicon,hi3670-dwc3" },
0179     { .compatible = "intel,keembay-dwc3" },
0180     { /* Sentinel */ }
0181 };
0182 MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
0183 
0184 static struct platform_driver dwc3_of_simple_driver = {
0185     .probe      = dwc3_of_simple_probe,
0186     .remove     = dwc3_of_simple_remove,
0187     .shutdown   = dwc3_of_simple_shutdown,
0188     .driver     = {
0189         .name   = "dwc3-of-simple",
0190         .of_match_table = of_dwc3_simple_match,
0191         .pm = &dwc3_of_simple_dev_pm_ops,
0192     },
0193 };
0194 
0195 module_platform_driver(dwc3_of_simple_driver);
0196 MODULE_LICENSE("GPL v2");
0197 MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
0198 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");