]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/blob - drivers/usb/dwc3/dwc3-of-simple.c
c69957b58f4a52e29b1f5238028e2a430e86ad0a
[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 =
144                 of_find_compatible_node(dev->of_node, NULL, "xlnx,zynqmp-dwc3");
145
146         if (node)  {
147                 struct platform_device *pdev_parent;
148                 struct dwc3_of_simple   *simple;
149
150                 pdev_parent = of_find_device_by_node(node);
151                 simple = platform_get_drvdata(pdev_parent);
152
153                 /* Set wakeup capable as true or false */
154                 simple->wakeup_capable = wakeup;
155         }
156 }
157 EXPORT_SYMBOL(dwc3_simple_wakeup_capable);
158
159 static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
160 {
161         struct device           *dev = simple->dev;
162         struct device_node      *np = dev->of_node;
163         int                     i;
164
165         simple->num_clocks = count;
166
167         if (!count)
168                 return 0;
169
170         simple->clks = devm_kcalloc(dev, simple->num_clocks,
171                         sizeof(struct clk *), GFP_KERNEL);
172         if (!simple->clks)
173                 return -ENOMEM;
174
175         for (i = 0; i < simple->num_clocks; i++) {
176                 struct clk      *clk;
177                 int             ret;
178
179                 clk = of_clk_get(np, i);
180                 if (IS_ERR(clk)) {
181                         while (--i >= 0)
182                                 clk_put(simple->clks[i]);
183                         return PTR_ERR(clk);
184                 }
185
186                 ret = clk_prepare_enable(clk);
187                 if (ret < 0) {
188                         while (--i >= 0) {
189                                 clk_disable_unprepare(simple->clks[i]);
190                                 clk_put(simple->clks[i]);
191                         }
192                         clk_put(clk);
193
194                         return ret;
195                 }
196
197                 simple->clks[i] = clk;
198         }
199
200         return 0;
201 }
202
203 static int dwc3_of_simple_probe(struct platform_device *pdev)
204 {
205         struct dwc3_of_simple   *simple;
206         struct device           *dev = &pdev->dev;
207         struct device_node      *np = dev->of_node;
208
209         int                     ret;
210         int                     i;
211
212         simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
213         if (!simple)
214                 return -ENOMEM;
215
216         platform_set_drvdata(pdev, simple);
217         simple->dev = dev;
218
219         if (of_device_is_compatible(pdev->dev.of_node,
220                                     "xlnx,zynqmp-dwc3")) {
221
222                 char                    *soc_rev;
223                 struct resource         *res;
224                 void __iomem            *regs;
225
226                 res = platform_get_resource(pdev,
227                                             IORESOURCE_MEM, 0);
228
229                 regs = devm_ioremap_resource(&pdev->dev, res);
230                 if (IS_ERR(regs))
231                         return PTR_ERR(regs);
232
233                 /* Store the usb control regs into simple for further usage */
234                 simple->regs = regs;
235
236                 /* read Silicon version using nvmem driver */
237                 soc_rev = zynqmp_nvmem_get_silicon_version(&pdev->dev,
238                                                    "soc_revision");
239
240                 if (PTR_ERR(soc_rev) == -EPROBE_DEFER) {
241                         /* Do a deferred probe */
242                         return -EPROBE_DEFER;
243
244                 } else if (!IS_ERR(soc_rev) &&
245                                         (*soc_rev < ZYNQMP_SILICON_V4)) {
246                         /* Add snps,dis_u3_susphy_quirk
247                          * for SOC revison less than v4
248                          */
249                         simple->dis_u3_susphy_quirk = true;
250                 }
251
252                 /* Clean soc_rev if got a valid pointer from nvmem driver
253                  * else we may end up in kernel panic
254                  */
255                 if (!IS_ERR(soc_rev))
256                         kfree(soc_rev);
257         }
258
259         ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np));
260         if (ret)
261                 return ret;
262
263         ret = of_platform_populate(np, NULL, NULL, dev);
264         if (ret) {
265                 for (i = 0; i < simple->num_clocks; i++) {
266                         clk_disable_unprepare(simple->clks[i]);
267                         clk_put(simple->clks[i]);
268                 }
269
270                 return ret;
271         }
272
273         platform_set_drvdata(pdev, simple);
274
275         pm_runtime_set_active(dev);
276         pm_runtime_enable(dev);
277         pm_runtime_get_sync(dev);
278
279         return 0;
280 }
281
282 static int dwc3_of_simple_remove(struct platform_device *pdev)
283 {
284         struct dwc3_of_simple   *simple = platform_get_drvdata(pdev);
285         struct device           *dev = &pdev->dev;
286         int                     i;
287
288         of_platform_depopulate(dev);
289
290         for (i = 0; i < simple->num_clocks; i++) {
291                 clk_disable_unprepare(simple->clks[i]);
292                 clk_put(simple->clks[i]);
293         }
294
295         pm_runtime_put_sync(dev);
296         pm_runtime_disable(dev);
297
298         return 0;
299 }
300
301 #ifdef CONFIG_PM
302
303 static void dwc3_simple_vbus(struct dwc3 *dwc, bool vbus_off)
304 {
305         u32 reg, addr;
306         u8  val;
307
308         if (vbus_off)
309                 addr = ULPI_OTG_CTRL_CLEAR;
310         else
311                 addr = ULPI_OTG_CTRL_SET;
312
313         val = (1 << OTG_CTRL_DRVVBUS_OFFSET);
314
315         reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_GUSB2PHYACC_ADDR(addr);
316         reg |= DWC3_GUSB2PHYACC_WRITE | val;
317
318         addr = DWC3_OF_ADDRESS(DWC3_GUSB2PHYACC(0));
319         writel(reg, dwc->regs + addr);
320 }
321
322 static int dwc3_of_simple_suspend(struct device *dev)
323 {
324         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
325         int                     i;
326
327         if (!simple->wakeup_capable) {
328                 /* Ask ULPI to turn OFF Vbus */
329                 dwc3_simple_vbus(simple->dwc, true);
330
331                 /* Disable the clocks */
332                 for (i = 0; i < simple->num_clocks; i++)
333                         clk_disable(simple->clks[i]);
334         }
335
336         return 0;
337 }
338
339 static int dwc3_of_simple_resume(struct device *dev)
340 {
341         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
342         int                     ret;
343         int                     i;
344
345         if (simple->wakeup_capable)
346                 return 0;
347
348         for (i = 0; i < simple->num_clocks; i++) {
349                 ret = clk_enable(simple->clks[i]);
350                 if (ret < 0) {
351                         while (--i >= 0)
352                                 clk_disable(simple->clks[i]);
353                         return ret;
354                 }
355
356                 /* Ask ULPI to turn ON Vbus */
357                 dwc3_simple_vbus(simple->dwc, false);
358         }
359
360         return 0;
361 }
362
363 static int dwc3_of_simple_runtime_suspend(struct device *dev)
364 {
365         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
366         int                     i;
367
368         for (i = 0; i < simple->num_clocks; i++)
369                 clk_disable(simple->clks[i]);
370
371         return 0;
372 }
373
374 static int dwc3_of_simple_runtime_resume(struct device *dev)
375 {
376         struct dwc3_of_simple   *simple = dev_get_drvdata(dev);
377         int                     ret;
378         int                     i;
379
380         for (i = 0; i < simple->num_clocks; i++) {
381                 ret = clk_enable(simple->clks[i]);
382                 if (ret < 0) {
383                         while (--i >= 0)
384                                 clk_disable(simple->clks[i]);
385                         return ret;
386                 }
387         }
388
389         return 0;
390 }
391 #endif
392
393 static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
394         SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend,
395                                 dwc3_of_simple_resume)
396         SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
397                         dwc3_of_simple_runtime_resume, NULL)
398 };
399
400 static const struct of_device_id of_dwc3_simple_match[] = {
401         { .compatible = "qcom,dwc3" },
402         { .compatible = "rockchip,rk3399-dwc3" },
403         { .compatible = "xlnx,zynqmp-dwc3" },
404         { .compatible = "cavium,octeon-7130-usb-uctl" },
405         { /* Sentinel */ }
406 };
407 MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
408
409 static struct platform_driver dwc3_of_simple_driver = {
410         .probe          = dwc3_of_simple_probe,
411         .remove         = dwc3_of_simple_remove,
412         .driver         = {
413                 .name   = "dwc3-of-simple",
414                 .of_match_table = of_dwc3_simple_match,
415                 .pm = &dwc3_of_simple_dev_pm_ops,
416         },
417 };
418
419 module_platform_driver(dwc3_of_simple_driver);
420 MODULE_LICENSE("GPL v2");
421 MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
422 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");