3c77bd3fed70cc6602540e07b7f076c35fc024b8
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc3 / dwc3-rockchip.c
1 /**
2  * dwc3-rockchip.c - Rockchip Specific Glue layer
3  *
4  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
5  *
6  * Authors: William Wu <william.wu@rock-chips.com>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2  of
10  * the License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/slab.h>
21 #include <linux/platform_device.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/clk.h>
24 #include <linux/clk-provider.h>
25 #include <linux/of.h>
26 #include <linux/of_platform.h>
27 #include <linux/pm_runtime.h>
28 #include <linux/extcon.h>
29 #include <linux/reset.h>
30 #include <linux/usb.h>
31 #include <linux/usb/hcd.h>
32
33 #include "core.h"
34 #include "io.h"
35
36 #define DWC3_ROCKCHIP_AUTOSUSPEND_DELAY  500 /* ms */
37
38 struct dwc3_rockchip {
39         int                     num_clocks;
40         bool                    connected;
41         struct device           *dev;
42         struct clk              **clks;
43         struct dwc3             *dwc;
44         struct reset_control    *otg_rst;
45         struct extcon_dev       *edev;
46         struct notifier_block   device_nb;
47         struct notifier_block   host_nb;
48         struct work_struct      otg_work;
49 };
50
51 static int dwc3_rockchip_device_notifier(struct notifier_block *nb,
52                                          unsigned long event, void *ptr)
53 {
54         struct dwc3_rockchip *rockchip =
55                 container_of(nb, struct dwc3_rockchip, device_nb);
56
57         schedule_work(&rockchip->otg_work);
58
59         return NOTIFY_DONE;
60 }
61
62 static int dwc3_rockchip_host_notifier(struct notifier_block *nb,
63                                        unsigned long event, void *ptr)
64 {
65         struct dwc3_rockchip *rockchip =
66                 container_of(nb, struct dwc3_rockchip, host_nb);
67
68         schedule_work(&rockchip->otg_work);
69
70         return NOTIFY_DONE;
71 }
72
73 static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
74 {
75         struct dwc3_rockchip    *rockchip =
76                 container_of(work, struct dwc3_rockchip, otg_work);
77         struct dwc3             *dwc = rockchip->dwc;
78         struct extcon_dev       *edev = rockchip->edev;
79         struct usb_hcd          *hcd;
80         unsigned long           flags;
81         int                     ret;
82         u32                     reg;
83
84         if (!dwc)
85                 return;
86
87         if (extcon_get_cable_state_(edev, EXTCON_USB) > 0) {
88                 if (rockchip->connected)
89                         return;
90
91                 /*
92                  * If dr_mode is host only, never to set
93                  * the mode to the peripheral mode.
94                  */
95                 if (WARN_ON(dwc->dr_mode == USB_DR_MODE_HOST))
96                         return;
97
98                 pm_runtime_get_sync(dwc->dev);
99
100                 spin_lock_irqsave(&dwc->lock, flags);
101                 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
102                 spin_unlock_irqrestore(&dwc->lock, flags);
103
104                 rockchip->connected = true;
105                 dev_info(rockchip->dev, "USB peripheral connected\n");
106         } else if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) > 0) {
107                 if (rockchip->connected)
108                         return;
109
110                 /*
111                  * If dr_mode is device only, never to
112                  * set the mode to the host mode.
113                  */
114                 if (WARN_ON(dwc->dr_mode == USB_DR_MODE_PERIPHERAL))
115                         return;
116
117                 reset_control_assert(rockchip->otg_rst);
118
119                 ret = phy_power_on(dwc->usb2_generic_phy);
120                 if (ret < 0)
121                         return;
122
123                 ret = phy_power_on(dwc->usb3_generic_phy);
124                 if (ret < 0)
125                         return;
126
127                 reset_control_deassert(rockchip->otg_rst);
128
129                 pm_runtime_get_sync(dwc->dev);
130
131                 hcd = dev_get_drvdata(&dwc->xhci->dev);
132
133                 spin_lock_irqsave(&dwc->lock, flags);
134                 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
135                 spin_unlock_irqrestore(&dwc->lock, flags);
136
137                 if (hcd->state == HC_STATE_HALT) {
138                         usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
139                         usb_add_hcd(hcd->shared_hcd, hcd->irq, IRQF_SHARED);
140                 }
141
142                 rockchip->connected = true;
143                 dev_info(rockchip->dev, "USB HOST connected\n");
144         } else {
145                 if (!rockchip->connected)
146                         return;
147
148                 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
149
150                 if (DWC3_GCTL_PRTCAP(reg) == DWC3_GCTL_PRTCAP_HOST ||
151                     DWC3_GCTL_PRTCAP(reg) == DWC3_GCTL_PRTCAP_OTG) {
152                         hcd = dev_get_drvdata(&dwc->xhci->dev);
153
154                         if (hcd->state != HC_STATE_HALT) {
155                                 usb_remove_hcd(hcd->shared_hcd);
156                                 usb_remove_hcd(hcd);
157                         }
158
159                         phy_power_off(dwc->usb2_generic_phy);
160                         phy_power_off(dwc->usb3_generic_phy);
161
162                 }
163
164                 pm_runtime_put_sync(dwc->dev);
165
166                 rockchip->connected = false;
167                 dev_info(rockchip->dev, "USB unconnected\n");
168         }
169 }
170
171 static int dwc3_rockchip_extcon_register(struct dwc3_rockchip *rockchip)
172 {
173         int                     ret;
174         struct device           *dev = rockchip->dev;
175         struct extcon_dev       *edev;
176
177         if (device_property_read_bool(dev, "extcon")) {
178                 edev = extcon_get_edev_by_phandle(dev, 0);
179                 if (IS_ERR(edev)) {
180                         if (PTR_ERR(edev) != -EPROBE_DEFER)
181                                 dev_err(dev, "couldn't get extcon device\n");
182                         return PTR_ERR(edev);
183                 }
184
185                 INIT_WORK(&rockchip->otg_work,
186                           dwc3_rockchip_otg_extcon_evt_work);
187
188                 rockchip->device_nb.notifier_call =
189                                 dwc3_rockchip_device_notifier;
190                 ret = extcon_register_notifier(edev, EXTCON_USB,
191                                                &rockchip->device_nb);
192                 if (ret < 0) {
193                         dev_err(dev, "failed to register notifier for USB\n");
194                         return ret;
195                 }
196
197                 rockchip->host_nb.notifier_call =
198                                 dwc3_rockchip_host_notifier;
199                 ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
200                                                &rockchip->host_nb);
201                 if (ret < 0) {
202                         dev_err(dev, "failed to register notifier for USB HOST\n");
203                         extcon_unregister_notifier(edev, EXTCON_USB,
204                                                    &rockchip->device_nb);
205                         return ret;
206                 }
207
208                 rockchip->edev = edev;
209         }
210
211         return 0;
212 }
213
214 static void dwc3_rockchip_extcon_unregister(struct dwc3_rockchip *rockchip)
215 {
216         if (!rockchip->edev)
217                 return;
218
219         extcon_unregister_notifier(rockchip->edev, EXTCON_USB,
220                                    &rockchip->device_nb);
221         extcon_unregister_notifier(rockchip->edev, EXTCON_USB_HOST,
222                                    &rockchip->host_nb);
223 }
224
225 static int dwc3_rockchip_probe(struct platform_device *pdev)
226 {
227         struct dwc3_rockchip    *rockchip;
228         struct device           *dev = &pdev->dev;
229         struct device_node      *np = dev->of_node, *child;
230         struct platform_device  *child_pdev;
231
232         unsigned int            count;
233         int                     ret;
234         int                     i;
235
236         rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
237
238         if (!rockchip)
239                 return -ENOMEM;
240
241         count = of_clk_get_parent_count(np);
242         if (!count)
243                 return -ENOENT;
244
245         rockchip->num_clocks = count;
246
247         rockchip->clks = devm_kcalloc(dev, rockchip->num_clocks,
248                                       sizeof(struct clk *), GFP_KERNEL);
249         if (!rockchip->clks)
250                 return -ENOMEM;
251
252         platform_set_drvdata(pdev, rockchip);
253
254         rockchip->dev = dev;
255         rockchip->edev = NULL;
256
257         for (i = 0; i < rockchip->num_clocks; i++) {
258                 struct clk      *clk;
259
260                 clk = of_clk_get(np, i);
261                 if (IS_ERR(clk)) {
262                         while (--i >= 0)
263                                 clk_put(rockchip->clks[i]);
264                         return PTR_ERR(clk);
265                 }
266
267                 ret = clk_prepare_enable(clk);
268                 if (ret < 0) {
269                         while (--i >= 0) {
270                                 clk_disable_unprepare(rockchip->clks[i]);
271                                 clk_put(rockchip->clks[i]);
272                         }
273                         clk_put(clk);
274
275                         return ret;
276                 }
277
278                 rockchip->clks[i] = clk;
279         }
280
281         pm_runtime_set_active(dev);
282         pm_runtime_enable(dev);
283         ret = pm_runtime_get_sync(dev);
284         if (ret < 0) {
285                 dev_err(dev, "get_sync failed with err %d\n", ret);
286                 goto err1;
287         }
288
289         rockchip->otg_rst = devm_reset_control_get(dev, "usb3-otg");
290         if (IS_ERR(rockchip->otg_rst)) {
291                 dev_err(dev, "could not get reset controller\n");
292                 ret = PTR_ERR(rockchip->otg_rst);
293                 goto err1;
294         }
295
296         ret = dwc3_rockchip_extcon_register(rockchip);
297         if (ret < 0)
298                 goto err1;
299
300         child = of_get_child_by_name(np, "dwc3");
301         if (!child) {
302                 dev_err(dev, "failed to find dwc3 core node\n");
303                 ret = -ENODEV;
304                 goto err2;
305         }
306
307         /* Allocate and initialize the core */
308         ret = of_platform_populate(np, NULL, NULL, dev);
309         if (ret) {
310                 dev_err(dev, "failed to create dwc3 core\n");
311                 goto err2;
312         }
313
314         child_pdev = of_find_device_by_node(child);
315         if (!child_pdev) {
316                 dev_err(dev, "failed to find dwc3 core device\n");
317                 ret = -ENODEV;
318                 goto err3;
319         }
320
321         rockchip->dwc = platform_get_drvdata(child_pdev);
322         if (!rockchip->dwc) {
323                 dev_err(dev, "failed to get drvdata dwc3\n");
324                 ret = -ENODEV;
325                 goto err3;
326         }
327
328         if (rockchip->edev) {
329                 pm_runtime_set_autosuspend_delay(&child_pdev->dev,
330                                                  DWC3_ROCKCHIP_AUTOSUSPEND_DELAY);
331                 pm_runtime_allow(&child_pdev->dev);
332
333                 if (rockchip->dwc->dr_mode == USB_DR_MODE_HOST ||
334                     rockchip->dwc->dr_mode == USB_DR_MODE_OTG) {
335                         struct usb_hcd *hcd =
336                                 dev_get_drvdata(&rockchip->dwc->xhci->dev);
337
338                         if (hcd->state != HC_STATE_HALT) {
339                                 usb_remove_hcd(hcd->shared_hcd);
340                                 usb_remove_hcd(hcd);
341                         }
342                 }
343
344                 pm_runtime_put_sync(dev);
345         }
346
347         return ret;
348
349 err3:
350         of_platform_depopulate(dev);
351
352 err2:
353         dwc3_rockchip_extcon_unregister(rockchip);
354
355 err1:
356         pm_runtime_put_sync(dev);
357         pm_runtime_disable(dev);
358
359         for (i = 0; i < rockchip->num_clocks; i++) {
360                 clk_unprepare(rockchip->clks[i]);
361                 clk_put(rockchip->clks[i]);
362         }
363
364         return ret;
365 }
366
367 static int dwc3_rockchip_remove(struct platform_device *pdev)
368 {
369         struct dwc3_rockchip    *rockchip = platform_get_drvdata(pdev);
370         struct device           *dev = &pdev->dev;
371         int                     i;
372
373         dwc3_rockchip_extcon_unregister(rockchip);
374
375         of_platform_depopulate(dev);
376
377         pm_runtime_put_sync(dev);
378         pm_runtime_disable(dev);
379
380         for (i = 0; i < rockchip->num_clocks; i++) {
381                 clk_unprepare(rockchip->clks[i]);
382                 clk_put(rockchip->clks[i]);
383         }
384
385         return 0;
386 }
387
388 #ifdef CONFIG_PM
389 static int dwc3_rockchip_runtime_suspend(struct device *dev)
390 {
391         struct dwc3_rockchip    *rockchip = dev_get_drvdata(dev);
392         int                     i;
393
394         for (i = 0; i < rockchip->num_clocks; i++)
395                 clk_disable(rockchip->clks[i]);
396
397         return 0;
398 }
399
400 static int dwc3_rockchip_runtime_resume(struct device *dev)
401 {
402         struct dwc3_rockchip    *rockchip = dev_get_drvdata(dev);
403         int                     i;
404
405         for (i = 0; i < rockchip->num_clocks; i++)
406                 clk_enable(rockchip->clks[i]);
407
408         return 0;
409 }
410
411 static const struct dev_pm_ops dwc3_rockchip_dev_pm_ops = {
412         SET_RUNTIME_PM_OPS(dwc3_rockchip_runtime_suspend,
413                            dwc3_rockchip_runtime_resume, NULL)
414 };
415
416 #define DEV_PM_OPS      (&dwc3_rockchip_dev_pm_ops)
417 #else
418 #define DEV_PM_OPS      NULL
419 #endif /* CONFIG_PM */
420
421 static const struct of_device_id rockchip_dwc3_match[] = {
422         { .compatible = "rockchip,rk3399-dwc3" },
423         { /* Sentinel */ }
424 };
425
426 MODULE_DEVICE_TABLE(of, rockchip_dwc3_match);
427
428 static struct platform_driver dwc3_rockchip_driver = {
429         .probe          = dwc3_rockchip_probe,
430         .remove         = dwc3_rockchip_remove,
431         .driver         = {
432                 .name   = "rockchip-dwc3",
433                 .of_match_table = rockchip_dwc3_match,
434                 .pm     = DEV_PM_OPS,
435         },
436 };
437
438 module_platform_driver(dwc3_rockchip_driver);
439
440 MODULE_ALIAS("platform:rockchip-dwc3");
441 MODULE_AUTHOR("William Wu <william.wu@rock-chips.com>");
442 MODULE_LICENSE("GPL v2");
443 MODULE_DESCRIPTION("DesignWare USB3 ROCKCHIP Glue Layer");