1 // SPDX-License-Identifier: GPL-2.0
3 * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com
8 * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/platform_device.h>
15 #include <linux/clk.h>
16 #include <linux/usb/otg.h>
17 #include <linux/usb/usb_phy_generic.h>
19 #include <linux/of_platform.h>
20 #include <linux/regulator/consumer.h>
23 struct platform_device
*usb2_phy
;
24 struct platform_device
*usb3_phy
;
29 struct clk
*axius_clk
;
31 struct regulator
*vdd33
;
32 struct regulator
*vdd10
;
35 static int dwc3_exynos_register_phys(struct dwc3_exynos
*exynos
)
37 struct usb_phy_generic_platform_data pdata
;
38 struct platform_device
*pdev
;
41 memset(&pdata
, 0x00, sizeof(pdata
));
43 pdev
= platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO
);
47 exynos
->usb2_phy
= pdev
;
48 pdata
.type
= USB_PHY_TYPE_USB2
;
49 pdata
.gpio_reset
= -1;
51 ret
= platform_device_add_data(exynos
->usb2_phy
, &pdata
, sizeof(pdata
));
55 pdev
= platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO
);
61 exynos
->usb3_phy
= pdev
;
62 pdata
.type
= USB_PHY_TYPE_USB3
;
64 ret
= platform_device_add_data(exynos
->usb3_phy
, &pdata
, sizeof(pdata
));
68 ret
= platform_device_add(exynos
->usb2_phy
);
72 ret
= platform_device_add(exynos
->usb3_phy
);
79 platform_device_del(exynos
->usb2_phy
);
82 platform_device_put(exynos
->usb3_phy
);
85 platform_device_put(exynos
->usb2_phy
);
90 static int dwc3_exynos_remove_child(struct device
*dev
, void *unused
)
92 struct platform_device
*pdev
= to_platform_device(dev
);
94 platform_device_unregister(pdev
);
99 static int dwc3_exynos_probe(struct platform_device
*pdev
)
101 struct dwc3_exynos
*exynos
;
102 struct device
*dev
= &pdev
->dev
;
103 struct device_node
*node
= dev
->of_node
;
107 exynos
= devm_kzalloc(dev
, sizeof(*exynos
), GFP_KERNEL
);
111 platform_set_drvdata(pdev
, exynos
);
115 exynos
->clk
= devm_clk_get(dev
, "usbdrd30");
116 if (IS_ERR(exynos
->clk
)) {
117 dev_err(dev
, "couldn't get clock\n");
120 ret
= clk_prepare_enable(exynos
->clk
);
124 exynos
->susp_clk
= devm_clk_get(dev
, "usbdrd30_susp_clk");
125 if (IS_ERR(exynos
->susp_clk
))
126 exynos
->susp_clk
= NULL
;
127 ret
= clk_prepare_enable(exynos
->susp_clk
);
131 if (of_device_is_compatible(node
, "samsung,exynos7-dwusb3")) {
132 exynos
->axius_clk
= devm_clk_get(dev
, "usbdrd30_axius_clk");
133 if (IS_ERR(exynos
->axius_clk
)) {
134 dev_err(dev
, "no AXI UpScaler clk specified\n");
138 ret
= clk_prepare_enable(exynos
->axius_clk
);
142 exynos
->axius_clk
= NULL
;
145 exynos
->vdd33
= devm_regulator_get(dev
, "vdd33");
146 if (IS_ERR(exynos
->vdd33
)) {
147 ret
= PTR_ERR(exynos
->vdd33
);
150 ret
= regulator_enable(exynos
->vdd33
);
152 dev_err(dev
, "Failed to enable VDD33 supply\n");
156 exynos
->vdd10
= devm_regulator_get(dev
, "vdd10");
157 if (IS_ERR(exynos
->vdd10
)) {
158 ret
= PTR_ERR(exynos
->vdd10
);
161 ret
= regulator_enable(exynos
->vdd10
);
163 dev_err(dev
, "Failed to enable VDD10 supply\n");
167 ret
= dwc3_exynos_register_phys(exynos
);
169 dev_err(dev
, "couldn't register PHYs\n");
174 ret
= of_platform_populate(node
, NULL
, NULL
, dev
);
176 dev_err(dev
, "failed to add dwc3 core\n");
180 dev_err(dev
, "no device node, failed to add dwc3 core\n");
188 platform_device_unregister(exynos
->usb2_phy
);
189 platform_device_unregister(exynos
->usb3_phy
);
191 regulator_disable(exynos
->vdd10
);
193 regulator_disable(exynos
->vdd33
);
195 clk_disable_unprepare(exynos
->axius_clk
);
197 clk_disable_unprepare(exynos
->susp_clk
);
199 clk_disable_unprepare(exynos
->clk
);
203 static int dwc3_exynos_remove(struct platform_device
*pdev
)
205 struct dwc3_exynos
*exynos
= platform_get_drvdata(pdev
);
207 device_for_each_child(&pdev
->dev
, NULL
, dwc3_exynos_remove_child
);
208 platform_device_unregister(exynos
->usb2_phy
);
209 platform_device_unregister(exynos
->usb3_phy
);
211 clk_disable_unprepare(exynos
->axius_clk
);
212 clk_disable_unprepare(exynos
->susp_clk
);
213 clk_disable_unprepare(exynos
->clk
);
215 regulator_disable(exynos
->vdd33
);
216 regulator_disable(exynos
->vdd10
);
221 static const struct of_device_id exynos_dwc3_match
[] = {
222 { .compatible
= "samsung,exynos5250-dwusb3" },
223 { .compatible
= "samsung,exynos7-dwusb3" },
226 MODULE_DEVICE_TABLE(of
, exynos_dwc3_match
);
228 #ifdef CONFIG_PM_SLEEP
229 static int dwc3_exynos_suspend(struct device
*dev
)
231 struct dwc3_exynos
*exynos
= dev_get_drvdata(dev
);
233 clk_disable(exynos
->axius_clk
);
234 clk_disable(exynos
->clk
);
236 regulator_disable(exynos
->vdd33
);
237 regulator_disable(exynos
->vdd10
);
242 static int dwc3_exynos_resume(struct device
*dev
)
244 struct dwc3_exynos
*exynos
= dev_get_drvdata(dev
);
247 ret
= regulator_enable(exynos
->vdd33
);
249 dev_err(dev
, "Failed to enable VDD33 supply\n");
252 ret
= regulator_enable(exynos
->vdd10
);
254 dev_err(dev
, "Failed to enable VDD10 supply\n");
258 clk_enable(exynos
->clk
);
259 clk_enable(exynos
->axius_clk
);
261 /* runtime set active to reflect active state. */
262 pm_runtime_disable(dev
);
263 pm_runtime_set_active(dev
);
264 pm_runtime_enable(dev
);
269 static const struct dev_pm_ops dwc3_exynos_dev_pm_ops
= {
270 SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend
, dwc3_exynos_resume
)
273 #define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops)
275 #define DEV_PM_OPS NULL
276 #endif /* CONFIG_PM_SLEEP */
278 static struct platform_driver dwc3_exynos_driver
= {
279 .probe
= dwc3_exynos_probe
,
280 .remove
= dwc3_exynos_remove
,
282 .name
= "exynos-dwc3",
283 .of_match_table
= exynos_dwc3_match
,
288 module_platform_driver(dwc3_exynos_driver
);
290 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
291 MODULE_LICENSE("GPL v2");
292 MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");