]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/blob - drivers/usb/dwc3/dwc3-of-simple.c
dwc3: fix the logic for finding parent node
[vajnamar/linux-xlnx.git] / drivers / usb / dwc3 / dwc3-of-simple.c
1 /**
2  * dwc3-of-simple.c - OF glue layer for simple integrations
3  *
4  * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
5  *
6  * Author: Felipe Balbi <balbi@ti.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  * This is a combination of the old dwc3-qcom.c by Ivan T. Ivanov
18  * <iivanov@mm-sol.com> and the original patch adding support for Xilinx' SoC
19  * by Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com>
20  */
21
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/slab.h>
25 #include <linux/platform_device.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/clk.h>
28 #include <linux/clk-provider.h>
29 #include <linux/of.h>
30 #include <linux/of_platform.h>
31 #include <linux/pm_runtime.h>
32 #include <linux/soc/xilinx/zynqmp/fw.h>
33 #include <linux/slab.h>
34
35 #include <linux/phy/phy-zynqmp.h>
36 #include <linux/of_address.h>
37
38 #include "core.h"
39
40 /* Xilinx USB 3.0 IP Register */
41 #define XLNX_USB_COHERENCY              0x005C
42 #define XLNX_USB_COHERENCY_ENABLE       0x1
43
44 /* ULPI control registers */
45 #define ULPI_OTG_CTRL_SET               0xB
46 #define ULPI_OTG_CTRL_CLEAR             0XC
47 #define OTG_CTRL_DRVVBUS_OFFSET         5
48
49 #define DWC3_OF_ADDRESS(ADDR)           ((ADDR) - DWC3_GLOBALS_REGS_START)
50
51 struct dwc3_of_simple {
52         struct device           *dev;
53         struct clk              **clks;
54         int                     num_clocks;
55         void __iomem            *regs;
56         struct dwc3             *dwc;
57         bool                    wakeup_capable;
58         bool                    dis_u3_susphy_quirk;
59 };
60
61 void dwc3_set_phydata(struct device *dev, struct phy *phy)
62 {
63         struct device_node *node = of_get_parent(dev->of_node);
64         int ret;
65
66         if ((node != NULL) &&
67                 of_device_is_compatible(node, "xlnx,zynqmp-dwc3")) {
68                 struct platform_device *pdev_parent;
69                 struct dwc3_of_simple   *simple;
70
71                 pdev_parent = of_find_device_by_node(node);
72                 simple = platform_get_drvdata(pdev_parent);
73
74                 /* assign USB vendor regs to phy lane */
75                 ret = xpsgtr_set_protregs(phy, simple->regs);
76                 if (ret) {
77                         dev_err(&pdev_parent->dev,
78                                 "Not able to set PHY data\n");
79                 }
80         }
81 }
82 EXPORT_SYMBOL(dwc3_set_phydata);
83
84 int dwc3_enable_hw_coherency(struct device *dev)
85 {
86         struct device_node *node = of_get_parent(dev->of_node);
87
88         if (of_device_is_compatible(node, "xlnx,zynqmp-dwc3")) {
89                 struct platform_device *pdev_parent;
90                 struct dwc3_of_simple *simple;
91                 void __iomem *regs;
92                 u32 reg;
93
94                 pdev_parent = of_find_device_by_node(node);
95                 simple = platform_get_drvdata(pdev_parent);
96                 regs = simple->regs;
97
98                 reg = readl(regs + XLNX_USB_COHERENCY);
99                 reg |= XLNX_USB_COHERENCY_ENABLE;
100                 writel(reg, regs + XLNX_USB_COHERENCY);
101         }
102
103         return 0;
104 }
105 EXPORT_SYMBOL(dwc3_enable_hw_coherency);
106
107 void dwc3_set_simple_data(struct dwc3 *dwc)
108 {
109         struct device_node *node = of_get_parent(dwc->dev->of_node);
110
111         if (node && of_device_is_compatible(node, "xlnx,zynqmp-dwc3")) {
112                 struct platform_device *pdev_parent;
113                 struct dwc3_of_simple   *simple;
114
115                 pdev_parent = of_find_device_by_node(node);
116                 simple = platform_get_drvdata(pdev_parent);
117
118                 /* Set (struct dwc3 *) to simple->dwc for future use */
119                 simple->dwc =  dwc;
120         }
121 }
122 EXPORT_SYMBOL(dwc3_set_simple_data);
123
124 void dwc3_simple_check_quirks(struct dwc3 *dwc)
125 {
126         struct device_node *node = of_get_parent(dwc->dev->of_node);
127
128         if (node && of_device_is_compatible(node, "xlnx,zynqmp-dwc3")) {
129                 struct platform_device *pdev_parent;
130                 struct dwc3_of_simple   *simple;
131
132                 pdev_parent = of_find_device_by_node(node);
133                 simple = platform_get_drvdata(pdev_parent);
134
135                 /* Add snps,dis_u3_susphy_quirk */
136                 dwc->dis_u3_susphy_quirk = simple->dis_u3_susphy_quirk;
137         }
138 }
139 EXPORT_SYMBOL(dwc3_simple_check_quirks);
140
141 void dwc3_simple_wakeup_capable(struct device *dev, bool wakeup)
142 {
143         struct device_node *node = of_node_get(dev->parent->of_node);
144
145         /* check for valid parent node */
146         while (node) {
147                 if (!of_device_is_compatible(node, "xlnx,zynqmp-dwc3"))
148                         node = of_get_next_parent(node);
149                 else
150                         break;
151         }
152
153         if (node)  {
154                 struct platform_device *pdev_parent;
155                 struct dwc3_of_simple   *simple;
156
157                 pdev_parent = of_find_device_by_node(node);
158                 simple = platform_get_drvdata(pdev_parent);
159
160                 /* Set wakeup capable as true or false */
161                 simple->wakeup_capable = wakeup;
162         }
163 }
164 EXPORT_SYMBOL(dwc3_simple_wakeup_capable);
165
166 static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
167 {
168         struct device           *dev = simple->dev;
169         struct device_node      *np = dev->of_node;
170         int                     i;
171
172         simple->num_clocks = count;
173
174         if (!count)
175                 return 0;
176
177         simple->clks = devm_kcalloc(dev, simple->num_clocks,
178                         sizeof(struct clk *), GFP_KERNEL);
179         if (!simple->clks)
180                 return -ENOMEM;
181
182         for (i = 0; i < simple->num_clocks; i++) {
183                 struct clk      *clk;
184                 int             ret;
185
186                 clk = of_clk_get(np, i);
187                 if (IS_ERR(clk)) {
188                         while (--i >= 0)
189                                 clk_put(simple->clks[i]);
190                         return PTR_ERR(clk);
191                 }
192
193                 ret = clk_prepare_enable(clk);
194                 if (ret < 0) {
195                         while (--i >= 0) {
196                                 clk_disable_unprepare(simple->clks[i]);
197                                 clk_put(simple->clks[i]);
198                         }
199                         clk_put(clk);
200
201                         return ret;
202                 }
203
204                 simple->clks[i] = clk;
205         }
206
207         return 0;
208 }
209
210 static int dwc3_of_simple_probe(struct platform_device *pdev)
211 {
212         struct dwc3_of_simple   *simple;
213         struct device           *dev = &pdev->dev;
214         struct device_node      *np = dev->of_node;
215
216         int                     ret;
217         int                     i;
218
219         simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
220         if (!simple)
221                 return -ENOMEM;
222
223         platform_set_drvdata(pdev, simple);
224         simple->dev = dev;
225
226         if (of_device_is_compatible(pdev->dev.of_node,
227                                     "xlnx,zynqmp-dwc3")) {
228
229                 char                    *soc_rev;
230                 struct resource         *res;
231                 void __iomem            *regs;
232
233                 res = platform_get_resource(pdev,
234                                             IORESOURCE_MEM, 0);
235
236                 regs = devm_ioremap_resource(&pdev->dev, res);
237                 if (IS_ERR(regs))
238                         return PTR_ERR(regs);
239
240                 /* Store the usb control regs into simple for further usage */
241                 simple->regs = regs;
242
243                 /* read Silicon version using nvmem driver */
244                 soc_rev = zynqmp_nvmem_get_silicon_version(&pdev->dev,
245                                                    "soc_revision");
246
247                 if (PTR_ERR(soc_rev) == -EPROBE_DEFER) {
248                         /* Do a deferred probe */
249                         return -EPROBE_DEFER;
250
251                 } else if (!IS_ERR(soc_rev) &&
252                                         (*soc_rev < ZYNQMP_SILICON_V4)) {
253                         /* Add snps,dis_u3_susphy_quirk
254                          * for SOC revison less than v4
255                          */
256                         simple->dis_u3_susphy_quirk = true;
257                 }
258
259                 /* Clean soc_rev if got a valid pointer from nvmem driver
260                  * else we may end up in kernel panic
261                  */
262                 if (!IS_ERR(soc_rev))
263                         kfree(soc_rev);
264         }
265
266         ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np));
267         if (ret)
268                 return ret;
269
270         ret = of_platform_populate(np, NULL, NULL, dev);
271         if (ret) {
272                 for (i = 0; i < simple->num_clocks; i++) {
273                         clk_disable_unprepare(simple->clks[i]);
274                         clk_put(simple->clks[i]);
275                 }
276
277                 return ret;
278         }
279
280         platform_set_drvdata(pdev, simple);
281
282         pm_runtime_set_active(dev);
283         pm_runtime_enable(dev);
284         pm_runtime_get_sync(dev);
285
286         return 0;
287 }
288
289 static int dwc3_of_simple_remove(struct platform_device *pdev)
290 {
291         struct dwc3_of_simple   *simple = platform_get_drvdata(pdev);
292         struct device           *dev = &pdev->dev;
293         int                     i;
294
295         of_platform_depopulate(dev);
296
297         for (i = 0; i < simple->num_clocks; i++) {
298                 clk_disable_unprepare(simple->clks[i]);
299                 clk_put(simple->clks[i]);
300         }
301
302         pm_runtime_put_sync(dev);
303         pm_runtime_disable(dev);
304
305         return 0;
306 }
307
308 #ifdef CONFIG_PM
309
310 static void dwc3_simple_vbus(struct dwc3 *dwc, bool vbus_off)
311 {
312         u32 reg, addr;
313         u8  val;
314
315         if (vbus_off)
316                 addr = ULPI_OTG_CTRL_CLEAR;
317         else
318                 addr = ULPI_OTG_CTRL_SET;
319
320         val = (1 << OTG_CTRL_DRVVBUS_OFFSET);
321
322         reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_GUSB2PHYACC_ADDR(addr);
323         reg |= DWC3_GUSB2PHYACC_WRITE | val;
324
325         addr = DWC3_OF_ADDRESS(DWC3_GUSB2PHYACC(0));
326         writel(reg, dwc->regs + addr);
327 }
328
329 static int dwc3_of_simple_suspend(struct device *dev)
330 {
331         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
332         int                     i;
333
334         if (!simple->wakeup_capable) {
335                 /* Ask ULPI to turn OFF Vbus */
336                 dwc3_simple_vbus(simple->dwc, true);
337
338                 /* Disable the clocks */
339                 for (i = 0; i < simple->num_clocks; i++)
340                         clk_disable(simple->clks[i]);
341         }
342
343         return 0;
344 }
345
346 static int dwc3_of_simple_resume(struct device *dev)
347 {
348         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
349         int                     ret;
350         int                     i;
351
352         if (simple->wakeup_capable)
353                 return 0;
354
355         for (i = 0; i < simple->num_clocks; i++) {
356                 ret = clk_enable(simple->clks[i]);
357                 if (ret < 0) {
358                         while (--i >= 0)
359                                 clk_disable(simple->clks[i]);
360                         return ret;
361                 }
362
363                 /* Ask ULPI to turn ON Vbus */
364                 dwc3_simple_vbus(simple->dwc, false);
365         }
366
367         return 0;
368 }
369
370 static int dwc3_of_simple_runtime_suspend(struct device *dev)
371 {
372         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
373         int                     i;
374
375         for (i = 0; i < simple->num_clocks; i++)
376                 clk_disable(simple->clks[i]);
377
378         return 0;
379 }
380
381 static int dwc3_of_simple_runtime_resume(struct device *dev)
382 {
383         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
384         int                     ret;
385         int                     i;
386
387         for (i = 0; i < simple->num_clocks; i++) {
388                 ret = clk_enable(simple->clks[i]);
389                 if (ret < 0) {
390                         while (--i >= 0)
391                                 clk_disable(simple->clks[i]);
392                         return ret;
393                 }
394         }
395
396         return 0;
397 }
398 #endif
399
400 static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
401         SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend,
402                                 dwc3_of_simple_resume)
403         SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
404                         dwc3_of_simple_runtime_resume, NULL)
405 };
406
407 static const struct of_device_id of_dwc3_simple_match[] = {
408         { .compatible = "qcom,dwc3" },
409         { .compatible = "rockchip,rk3399-dwc3" },
410         { .compatible = "xlnx,zynqmp-dwc3" },
411         { .compatible = "cavium,octeon-7130-usb-uctl" },
412         { /* Sentinel */ }
413 };
414 MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
415
416 static struct platform_driver dwc3_of_simple_driver = {
417         .probe          = dwc3_of_simple_probe,
418         .remove         = dwc3_of_simple_remove,
419         .driver         = {
420                 .name   = "dwc3-of-simple",
421                 .of_match_table = of_dwc3_simple_match,
422                 .pm = &dwc3_of_simple_dev_pm_ops,
423         },
424 };
425
426 module_platform_driver(dwc3_of_simple_driver);
427 MODULE_LICENSE("GPL v2");
428 MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
429 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");