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>
17 #include <linux/of_platform.h>
18 #include <linux/regulator/consumer.h>
20 #define DWC3_EXYNOS_MAX_CLOCKS 4
22 struct dwc3_exynos_driverdata
{
23 const char *clk_names
[DWC3_EXYNOS_MAX_CLOCKS
];
31 const char **clk_names
;
32 struct clk
*clks
[DWC3_EXYNOS_MAX_CLOCKS
];
36 struct regulator
*vdd33
;
37 struct regulator
*vdd10
;
40 static int dwc3_exynos_probe(struct platform_device
*pdev
)
42 struct dwc3_exynos
*exynos
;
43 struct device
*dev
= &pdev
->dev
;
44 struct device_node
*node
= dev
->of_node
;
45 const struct dwc3_exynos_driverdata
*driver_data
;
48 exynos
= devm_kzalloc(dev
, sizeof(*exynos
), GFP_KERNEL
);
52 driver_data
= of_device_get_match_data(dev
);
54 exynos
->num_clks
= driver_data
->num_clks
;
55 exynos
->clk_names
= (const char **)driver_data
->clk_names
;
56 exynos
->suspend_clk_idx
= driver_data
->suspend_clk_idx
;
58 platform_set_drvdata(pdev
, exynos
);
60 for (i
= 0; i
< exynos
->num_clks
; i
++) {
61 exynos
->clks
[i
] = devm_clk_get(dev
, exynos
->clk_names
[i
]);
62 if (IS_ERR(exynos
->clks
[i
])) {
63 dev_err(dev
, "failed to get clock: %s\n",
64 exynos
->clk_names
[i
]);
65 return PTR_ERR(exynos
->clks
[i
]);
69 for (i
= 0; i
< exynos
->num_clks
; i
++) {
70 ret
= clk_prepare_enable(exynos
->clks
[i
]);
73 clk_disable_unprepare(exynos
->clks
[i
]);
78 if (exynos
->suspend_clk_idx
>= 0)
79 clk_prepare_enable(exynos
->clks
[exynos
->suspend_clk_idx
]);
81 exynos
->vdd33
= devm_regulator_get(dev
, "vdd33");
82 if (IS_ERR(exynos
->vdd33
)) {
83 ret
= PTR_ERR(exynos
->vdd33
);
86 ret
= regulator_enable(exynos
->vdd33
);
88 dev_err(dev
, "Failed to enable VDD33 supply\n");
92 exynos
->vdd10
= devm_regulator_get(dev
, "vdd10");
93 if (IS_ERR(exynos
->vdd10
)) {
94 ret
= PTR_ERR(exynos
->vdd10
);
97 ret
= regulator_enable(exynos
->vdd10
);
99 dev_err(dev
, "Failed to enable VDD10 supply\n");
104 ret
= of_platform_populate(node
, NULL
, NULL
, dev
);
106 dev_err(dev
, "failed to add dwc3 core\n");
110 dev_err(dev
, "no device node, failed to add dwc3 core\n");
118 regulator_disable(exynos
->vdd10
);
120 regulator_disable(exynos
->vdd33
);
122 for (i
= exynos
->num_clks
- 1; i
>= 0; i
--)
123 clk_disable_unprepare(exynos
->clks
[i
]);
125 if (exynos
->suspend_clk_idx
>= 0)
126 clk_disable_unprepare(exynos
->clks
[exynos
->suspend_clk_idx
]);
131 static void dwc3_exynos_remove(struct platform_device
*pdev
)
133 struct dwc3_exynos
*exynos
= platform_get_drvdata(pdev
);
136 of_platform_depopulate(&pdev
->dev
);
138 for (i
= exynos
->num_clks
- 1; i
>= 0; i
--)
139 clk_disable_unprepare(exynos
->clks
[i
]);
141 if (exynos
->suspend_clk_idx
>= 0)
142 clk_disable_unprepare(exynos
->clks
[exynos
->suspend_clk_idx
]);
144 regulator_disable(exynos
->vdd33
);
145 regulator_disable(exynos
->vdd10
);
148 static const struct dwc3_exynos_driverdata exynos5250_drvdata
= {
149 .clk_names
= { "usbdrd30" },
151 .suspend_clk_idx
= -1,
154 static const struct dwc3_exynos_driverdata exynos5433_drvdata
= {
155 .clk_names
= { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
157 .suspend_clk_idx
= 1,
160 static const struct dwc3_exynos_driverdata exynos7_drvdata
= {
161 .clk_names
= { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" },
163 .suspend_clk_idx
= 1,
166 static const struct dwc3_exynos_driverdata exynos850_drvdata
= {
167 .clk_names
= { "bus_early", "ref" },
169 .suspend_clk_idx
= -1,
172 static const struct dwc3_exynos_driverdata gs101_drvdata
= {
173 .clk_names
= { "bus_early", "susp_clk", "link_aclk", "link_pclk" },
175 .suspend_clk_idx
= 1,
178 static const struct of_device_id exynos_dwc3_match
[] = {
180 .compatible
= "samsung,exynos5250-dwusb3",
181 .data
= &exynos5250_drvdata
,
183 .compatible
= "samsung,exynos5433-dwusb3",
184 .data
= &exynos5433_drvdata
,
186 .compatible
= "samsung,exynos7-dwusb3",
187 .data
= &exynos7_drvdata
,
189 .compatible
= "samsung,exynos850-dwusb3",
190 .data
= &exynos850_drvdata
,
192 .compatible
= "google,gs101-dwusb3",
193 .data
= &gs101_drvdata
,
197 MODULE_DEVICE_TABLE(of
, exynos_dwc3_match
);
199 static int dwc3_exynos_suspend(struct device
*dev
)
201 struct dwc3_exynos
*exynos
= dev_get_drvdata(dev
);
204 for (i
= exynos
->num_clks
- 1; i
>= 0; i
--)
205 clk_disable_unprepare(exynos
->clks
[i
]);
207 regulator_disable(exynos
->vdd33
);
208 regulator_disable(exynos
->vdd10
);
213 static int dwc3_exynos_resume(struct device
*dev
)
215 struct dwc3_exynos
*exynos
= dev_get_drvdata(dev
);
218 ret
= regulator_enable(exynos
->vdd33
);
220 dev_err(dev
, "Failed to enable VDD33 supply\n");
223 ret
= regulator_enable(exynos
->vdd10
);
225 dev_err(dev
, "Failed to enable VDD10 supply\n");
229 for (i
= 0; i
< exynos
->num_clks
; i
++) {
230 ret
= clk_prepare_enable(exynos
->clks
[i
]);
233 clk_disable_unprepare(exynos
->clks
[i
]);
241 static DEFINE_SIMPLE_DEV_PM_OPS(dwc3_exynos_dev_pm_ops
,
242 dwc3_exynos_suspend
, dwc3_exynos_resume
);
244 static struct platform_driver dwc3_exynos_driver
= {
245 .probe
= dwc3_exynos_probe
,
246 .remove
= dwc3_exynos_remove
,
248 .name
= "exynos-dwc3",
249 .of_match_table
= exynos_dwc3_match
,
250 .pm
= pm_sleep_ptr(&dwc3_exynos_dev_pm_ops
),
254 module_platform_driver(dwc3_exynos_driver
);
256 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
257 MODULE_LICENSE("GPL v2");
258 MODULE_DESCRIPTION("DesignWare USB3 Exynos Glue Layer");