]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/usb/dwc3/dwc3-exynos.c
usb: dwc3: exynos: Remove local variable for clock from probe
[linux.git] / drivers / usb / dwc3 / dwc3-exynos.c
1 /**
2  * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5  *              http://www.samsung.com
6  *
7  * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2  of
11  * the License as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/platform_device.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/clk.h>
25 #include <linux/usb/otg.h>
26 #include <linux/usb/usb_phy_generic.h>
27 #include <linux/of.h>
28 #include <linux/of_platform.h>
29 #include <linux/regulator/consumer.h>
30
31 struct dwc3_exynos {
32         struct platform_device  *usb2_phy;
33         struct platform_device  *usb3_phy;
34         struct device           *dev;
35
36         struct clk              *clk;
37         struct regulator        *vdd33;
38         struct regulator        *vdd10;
39 };
40
41 static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
42 {
43         struct usb_phy_generic_platform_data pdata;
44         struct platform_device  *pdev;
45         int                     ret;
46
47         memset(&pdata, 0x00, sizeof(pdata));
48
49         pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);
50         if (!pdev)
51                 return -ENOMEM;
52
53         exynos->usb2_phy = pdev;
54         pdata.type = USB_PHY_TYPE_USB2;
55         pdata.gpio_reset = -1;
56
57         ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
58         if (ret)
59                 goto err1;
60
61         pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);
62         if (!pdev) {
63                 ret = -ENOMEM;
64                 goto err1;
65         }
66
67         exynos->usb3_phy = pdev;
68         pdata.type = USB_PHY_TYPE_USB3;
69
70         ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata));
71         if (ret)
72                 goto err2;
73
74         ret = platform_device_add(exynos->usb2_phy);
75         if (ret)
76                 goto err2;
77
78         ret = platform_device_add(exynos->usb3_phy);
79         if (ret)
80                 goto err3;
81
82         return 0;
83
84 err3:
85         platform_device_del(exynos->usb2_phy);
86
87 err2:
88         platform_device_put(exynos->usb3_phy);
89
90 err1:
91         platform_device_put(exynos->usb2_phy);
92
93         return ret;
94 }
95
96 static int dwc3_exynos_remove_child(struct device *dev, void *unused)
97 {
98         struct platform_device *pdev = to_platform_device(dev);
99
100         platform_device_unregister(pdev);
101
102         return 0;
103 }
104
105 static int dwc3_exynos_probe(struct platform_device *pdev)
106 {
107         struct dwc3_exynos      *exynos;
108         struct device           *dev = &pdev->dev;
109         struct device_node      *node = dev->of_node;
110
111         int                     ret;
112
113         exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
114         if (!exynos)
115                 return -ENOMEM;
116
117         /*
118          * Right now device-tree probed devices don't get dma_mask set.
119          * Since shared usb code relies on it, set it here for now.
120          * Once we move to full device tree support this will vanish off.
121          */
122         ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
123         if (ret)
124                 return ret;
125
126         platform_set_drvdata(pdev, exynos);
127
128         ret = dwc3_exynos_register_phys(exynos);
129         if (ret) {
130                 dev_err(dev, "couldn't register PHYs\n");
131                 return ret;
132         }
133
134         exynos->dev     = dev;
135
136         exynos->clk = devm_clk_get(dev, "usbdrd30");
137         if (IS_ERR(exynos->clk)) {
138                 dev_err(dev, "couldn't get clock\n");
139                 return -EINVAL;
140         }
141         clk_prepare_enable(exynos->clk);
142
143         exynos->vdd33 = devm_regulator_get(dev, "vdd33");
144         if (IS_ERR(exynos->vdd33)) {
145                 ret = PTR_ERR(exynos->vdd33);
146                 goto err2;
147         }
148         ret = regulator_enable(exynos->vdd33);
149         if (ret) {
150                 dev_err(dev, "Failed to enable VDD33 supply\n");
151                 goto err2;
152         }
153
154         exynos->vdd10 = devm_regulator_get(dev, "vdd10");
155         if (IS_ERR(exynos->vdd10)) {
156                 ret = PTR_ERR(exynos->vdd10);
157                 goto err3;
158         }
159         ret = regulator_enable(exynos->vdd10);
160         if (ret) {
161                 dev_err(dev, "Failed to enable VDD10 supply\n");
162                 goto err3;
163         }
164
165         if (node) {
166                 ret = of_platform_populate(node, NULL, NULL, dev);
167                 if (ret) {
168                         dev_err(dev, "failed to add dwc3 core\n");
169                         goto err4;
170                 }
171         } else {
172                 dev_err(dev, "no device node, failed to add dwc3 core\n");
173                 ret = -ENODEV;
174                 goto err4;
175         }
176
177         return 0;
178
179 err4:
180         regulator_disable(exynos->vdd10);
181 err3:
182         regulator_disable(exynos->vdd33);
183 err2:
184         clk_disable_unprepare(exynos->clk);
185         return ret;
186 }
187
188 static int dwc3_exynos_remove(struct platform_device *pdev)
189 {
190         struct dwc3_exynos      *exynos = platform_get_drvdata(pdev);
191
192         device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
193         platform_device_unregister(exynos->usb2_phy);
194         platform_device_unregister(exynos->usb3_phy);
195
196         clk_disable_unprepare(exynos->clk);
197
198         regulator_disable(exynos->vdd33);
199         regulator_disable(exynos->vdd10);
200
201         return 0;
202 }
203
204 static const struct of_device_id exynos_dwc3_match[] = {
205         { .compatible = "samsung,exynos5250-dwusb3" },
206         {},
207 };
208 MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
209
210 #ifdef CONFIG_PM_SLEEP
211 static int dwc3_exynos_suspend(struct device *dev)
212 {
213         struct dwc3_exynos *exynos = dev_get_drvdata(dev);
214
215         clk_disable(exynos->clk);
216
217         regulator_disable(exynos->vdd33);
218         regulator_disable(exynos->vdd10);
219
220         return 0;
221 }
222
223 static int dwc3_exynos_resume(struct device *dev)
224 {
225         struct dwc3_exynos *exynos = dev_get_drvdata(dev);
226         int ret;
227
228         ret = regulator_enable(exynos->vdd33);
229         if (ret) {
230                 dev_err(dev, "Failed to enable VDD33 supply\n");
231                 return ret;
232         }
233         ret = regulator_enable(exynos->vdd10);
234         if (ret) {
235                 dev_err(dev, "Failed to enable VDD10 supply\n");
236                 return ret;
237         }
238
239         clk_enable(exynos->clk);
240
241         /* runtime set active to reflect active state. */
242         pm_runtime_disable(dev);
243         pm_runtime_set_active(dev);
244         pm_runtime_enable(dev);
245
246         return 0;
247 }
248
249 static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
250         SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
251 };
252
253 #define DEV_PM_OPS      (&dwc3_exynos_dev_pm_ops)
254 #else
255 #define DEV_PM_OPS      NULL
256 #endif /* CONFIG_PM_SLEEP */
257
258 static struct platform_driver dwc3_exynos_driver = {
259         .probe          = dwc3_exynos_probe,
260         .remove         = dwc3_exynos_remove,
261         .driver         = {
262                 .name   = "exynos-dwc3",
263                 .of_match_table = exynos_dwc3_match,
264                 .pm     = DEV_PM_OPS,
265         },
266 };
267
268 module_platform_driver(dwc3_exynos_driver);
269
270 MODULE_ALIAS("platform:exynos-dwc3");
271 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
272 MODULE_LICENSE("GPL v2");
273 MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");