Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / usb / dwc3 / dwc3-qcom.c
1 /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12
13 #include <linux/clk.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/of_platform.h>
19 #include <linux/platform_device.h>
20
21 struct dwc3_qcom {
22         struct device           *dev;
23
24         struct clk              *core_clk;
25         struct clk              *iface_clk;
26         struct clk              *sleep_clk;
27 };
28
29 static int dwc3_qcom_probe(struct platform_device *pdev)
30 {
31         struct device_node *node = pdev->dev.of_node;
32         struct dwc3_qcom *qdwc;
33         int ret;
34
35         qdwc = devm_kzalloc(&pdev->dev, sizeof(*qdwc), GFP_KERNEL);
36         if (!qdwc)
37                 return -ENOMEM;
38
39         platform_set_drvdata(pdev, qdwc);
40
41         qdwc->dev = &pdev->dev;
42
43         qdwc->core_clk = devm_clk_get(qdwc->dev, "core");
44         if (IS_ERR(qdwc->core_clk)) {
45                 dev_err(qdwc->dev, "failed to get core clock\n");
46                 return PTR_ERR(qdwc->core_clk);
47         }
48
49         qdwc->iface_clk = devm_clk_get(qdwc->dev, "iface");
50         if (IS_ERR(qdwc->iface_clk)) {
51                 dev_dbg(qdwc->dev, "failed to get optional iface clock\n");
52                 qdwc->iface_clk = NULL;
53         }
54
55         qdwc->sleep_clk = devm_clk_get(qdwc->dev, "sleep");
56         if (IS_ERR(qdwc->sleep_clk)) {
57                 dev_dbg(qdwc->dev, "failed to get optional sleep clock\n");
58                 qdwc->sleep_clk = NULL;
59         }
60
61         ret = clk_prepare_enable(qdwc->core_clk);
62         if (ret) {
63                 dev_err(qdwc->dev, "failed to enable core clock\n");
64                 goto err_core;
65         }
66
67         ret = clk_prepare_enable(qdwc->iface_clk);
68         if (ret) {
69                 dev_err(qdwc->dev, "failed to enable optional iface clock\n");
70                 goto err_iface;
71         }
72
73         ret = clk_prepare_enable(qdwc->sleep_clk);
74         if (ret) {
75                 dev_err(qdwc->dev, "failed to enable optional sleep clock\n");
76                 goto err_sleep;
77         }
78
79         ret = of_platform_populate(node, NULL, NULL, qdwc->dev);
80         if (ret) {
81                 dev_err(qdwc->dev, "failed to register core - %d\n", ret);
82                 goto err_clks;
83         }
84
85         return 0;
86
87 err_clks:
88         clk_disable_unprepare(qdwc->sleep_clk);
89 err_sleep:
90         clk_disable_unprepare(qdwc->iface_clk);
91 err_iface:
92         clk_disable_unprepare(qdwc->core_clk);
93 err_core:
94         return ret;
95 }
96
97 static int dwc3_qcom_remove(struct platform_device *pdev)
98 {
99         struct dwc3_qcom *qdwc = platform_get_drvdata(pdev);
100
101         of_platform_depopulate(&pdev->dev);
102
103         clk_disable_unprepare(qdwc->sleep_clk);
104         clk_disable_unprepare(qdwc->iface_clk);
105         clk_disable_unprepare(qdwc->core_clk);
106
107         return 0;
108 }
109
110 static const struct of_device_id of_dwc3_match[] = {
111         { .compatible = "qcom,dwc3" },
112         { /* Sentinel */ }
113 };
114 MODULE_DEVICE_TABLE(of, of_dwc3_match);
115
116 static struct platform_driver dwc3_qcom_driver = {
117         .probe          = dwc3_qcom_probe,
118         .remove         = dwc3_qcom_remove,
119         .driver         = {
120                 .name   = "qcom-dwc3",
121                 .of_match_table = of_dwc3_match,
122         },
123 };
124
125 module_platform_driver(dwc3_qcom_driver);
126
127 MODULE_ALIAS("platform:qcom-dwc3");
128 MODULE_LICENSE("GPL v2");
129 MODULE_DESCRIPTION("DesignWare USB3 QCOM Glue Layer");
130 MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");