1 // SPDX-License-Identifier: GPL-2.0
3 * dwc3-of-simple.c - OF glue layer for simple integrations
5 * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
7 * Author: Felipe Balbi <balbi@ti.com>
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>
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>
21 #include <linux/of_platform.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/reset.h>
25 struct dwc3_of_simple
{
29 struct reset_control
*resets
;
33 static int dwc3_of_simple_clk_init(struct dwc3_of_simple
*simple
, int count
)
35 struct device
*dev
= simple
->dev
;
36 struct device_node
*np
= dev
->of_node
;
39 simple
->num_clocks
= count
;
44 simple
->clks
= devm_kcalloc(dev
, simple
->num_clocks
,
45 sizeof(struct clk
*), GFP_KERNEL
);
49 for (i
= 0; i
< simple
->num_clocks
; i
++) {
53 clk
= of_clk_get(np
, i
);
56 clk_disable_unprepare(simple
->clks
[i
]);
57 clk_put(simple
->clks
[i
]);
62 ret
= clk_prepare_enable(clk
);
65 clk_disable_unprepare(simple
->clks
[i
]);
66 clk_put(simple
->clks
[i
]);
73 simple
->clks
[i
] = clk
;
79 static int dwc3_of_simple_probe(struct platform_device
*pdev
)
81 struct dwc3_of_simple
*simple
;
82 struct device
*dev
= &pdev
->dev
;
83 struct device_node
*np
= dev
->of_node
;
87 bool shared_resets
= false;
89 simple
= devm_kzalloc(dev
, sizeof(*simple
), GFP_KERNEL
);
93 platform_set_drvdata(pdev
, simple
);
96 if (of_device_is_compatible(np
, "amlogic,meson-axg-dwc3") ||
97 of_device_is_compatible(np
, "amlogic,meson-gxl-dwc3")) {
99 simple
->pulse_resets
= true;
102 simple
->resets
= of_reset_control_array_get(np
, shared_resets
, true);
103 if (IS_ERR(simple
->resets
)) {
104 ret
= PTR_ERR(simple
->resets
);
105 dev_err(dev
, "failed to get device resets, err=%d\n", ret
);
109 if (simple
->pulse_resets
) {
110 ret
= reset_control_reset(simple
->resets
);
114 ret
= reset_control_deassert(simple
->resets
);
119 ret
= dwc3_of_simple_clk_init(simple
, of_count_phandle_with_args(np
,
120 "clocks", "#clock-cells"));
122 goto err_resetc_assert
;
124 ret
= of_platform_populate(np
, NULL
, NULL
, dev
);
126 for (i
= 0; i
< simple
->num_clocks
; i
++) {
127 clk_disable_unprepare(simple
->clks
[i
]);
128 clk_put(simple
->clks
[i
]);
131 goto err_resetc_assert
;
134 pm_runtime_set_active(dev
);
135 pm_runtime_enable(dev
);
136 pm_runtime_get_sync(dev
);
141 if (!simple
->pulse_resets
)
142 reset_control_assert(simple
->resets
);
145 reset_control_put(simple
->resets
);
149 static int dwc3_of_simple_remove(struct platform_device
*pdev
)
151 struct dwc3_of_simple
*simple
= platform_get_drvdata(pdev
);
152 struct device
*dev
= &pdev
->dev
;
155 of_platform_depopulate(dev
);
157 for (i
= 0; i
< simple
->num_clocks
; i
++) {
158 clk_disable_unprepare(simple
->clks
[i
]);
159 clk_put(simple
->clks
[i
]);
161 simple
->num_clocks
= 0;
163 if (!simple
->pulse_resets
)
164 reset_control_assert(simple
->resets
);
166 reset_control_put(simple
->resets
);
168 pm_runtime_put_sync(dev
);
169 pm_runtime_disable(dev
);
175 static int dwc3_of_simple_runtime_suspend(struct device
*dev
)
177 struct dwc3_of_simple
*simple
= dev_get_drvdata(dev
);
180 for (i
= 0; i
< simple
->num_clocks
; i
++)
181 clk_disable(simple
->clks
[i
]);
186 static int dwc3_of_simple_runtime_resume(struct device
*dev
)
188 struct dwc3_of_simple
*simple
= dev_get_drvdata(dev
);
192 for (i
= 0; i
< simple
->num_clocks
; i
++) {
193 ret
= clk_enable(simple
->clks
[i
]);
196 clk_disable(simple
->clks
[i
]);
205 static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops
= {
206 SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend
,
207 dwc3_of_simple_runtime_resume
, NULL
)
210 static const struct of_device_id of_dwc3_simple_match
[] = {
211 { .compatible
= "qcom,dwc3" },
212 { .compatible
= "rockchip,rk3399-dwc3" },
213 { .compatible
= "xlnx,zynqmp-dwc3" },
214 { .compatible
= "cavium,octeon-7130-usb-uctl" },
215 { .compatible
= "sprd,sc9860-dwc3" },
216 { .compatible
= "amlogic,meson-axg-dwc3" },
217 { .compatible
= "amlogic,meson-gxl-dwc3" },
220 MODULE_DEVICE_TABLE(of
, of_dwc3_simple_match
);
222 static struct platform_driver dwc3_of_simple_driver
= {
223 .probe
= dwc3_of_simple_probe
,
224 .remove
= dwc3_of_simple_remove
,
226 .name
= "dwc3-of-simple",
227 .of_match_table
= of_dwc3_simple_match
,
228 .pm
= &dwc3_of_simple_dev_pm_ops
,
232 module_platform_driver(dwc3_of_simple_driver
);
233 MODULE_LICENSE("GPL v2");
234 MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
235 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");