packages: enable AP mode on r8188eu
[openwrt.git] / target / linux / sunxi / patches-3.13 / 180-2-usb-ehci-platform-support-clk-phy-via-dt.patch
1 From 543824fa2a8a592a6eec0e0053063284980dc378 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Sun, 5 Jan 2014 00:04:02 +0100
4 Subject: [PATCH] ehci-platform: Add support for clks and phy passed through
5  devicetree
6
7 Currently ehci-platform is only used in combination with devicetree when used
8 with some Via socs. By extending it to (optionally) get clks and a phy from
9 devicetree, and enabling / disabling those on power_on / off, it can be used
10 more generically. Specifically after this commit it can be used for the
11 ehci controller on Allwinner sunxi SoCs.
12
13 Since ehci-platform is intended to handle any generic enough non pci ehci
14 device, add a "usb-ehci" compatibility string.
15
16 There already is a usb-ehci device-tree bindings document, update this
17 with clks and phy bindings info.
18
19 Although actually quite generic so far the via,vt8500 compatibilty string
20 had its own bindings document. Somehow we even ended up with 2 of them. Since
21 these provide no extra information over the generic usb-ehci documentation,
22 this patch removes them.
23
24 The ehci-ppc-of.c driver also claims the usb-ehci compatibility string,
25 even though it mostly is ibm,usb-ehci-440epx specific. ehci-platform.c is
26 not needed on ppc platforms, so add a !PPC_OF dependency to it to avoid
27 2 drivers claiming the same compatibility string getting build on ppc.
28
29 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
30 Acked-by: Alan Stern <stern@rowland.harvard.edu>
31 ---
32  Documentation/devicetree/bindings/usb/usb-ehci.txt |  25 +++-
33  .../devicetree/bindings/usb/via,vt8500-ehci.txt    |  15 ---
34  .../devicetree/bindings/usb/vt8500-ehci.txt        |  12 --
35  drivers/usb/host/Kconfig                           |   1 +
36  drivers/usb/host/ehci-platform.c                   | 147 +++++++++++++++++----
37  5 files changed, 142 insertions(+), 58 deletions(-)
38  delete mode 100644 Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
39  delete mode 100644 Documentation/devicetree/bindings/usb/vt8500-ehci.txt
40
41 diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
42 index fa18612..2c1aeeb 100644
43 --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
44 +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
45 @@ -7,13 +7,14 @@ Required properties:
46      (debug-port or other) can be also specified here, but only after
47      definition of standard EHCI registers.
48    - interrupts : one EHCI interrupt should be described here.
49 -If device registers are implemented in big endian mode, the device
50 -node should have "big-endian-regs" property.
51 -If controller implementation operates with big endian descriptors,
52 -"big-endian-desc" property should be specified.
53 -If both big endian registers and descriptors are used by the controller
54 -implementation, "big-endian" property can be specified instead of having
55 -both "big-endian-regs" and "big-endian-desc".
56 +
57 +Optional properties:
58 + - big-endian-regs : boolean, set this for hcds with big-endian registers
59 + - big-endian-desc : boolean, set this for hcds with big-endian descriptors
60 + - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
61 + - clocks : a list of phandle + clock specifier pairs
62 + - phys : phandle + phy specifier pair
63 + - phy-names : "usb"
64  
65  Example (Sequoia 440EPx):
66      ehci@e0000300 {
67 @@ -23,3 +24,13 @@ Example (Sequoia 440EPx):
68            reg = <0 e0000300 90 0 e0000390 70>;
69            big-endian;
70     };
71 +
72 +Example (Allwinner sun4i A10 SoC):
73 +   ehci0: usb@01c14000 {
74 +          compatible = "allwinner,sun4i-a10-ehci", "usb-ehci";
75 +          reg = <0x01c14000 0x100>;
76 +          interrupts = <39>;
77 +          clocks = <&ahb_gates 1>;
78 +          phys = <&usbphy 1>;
79 +          phy-names = "usb";
80 +   };
81 diff --git a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
82 deleted file mode 100644
83 index 17b3ad1..0000000
84 --- a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
85 +++ /dev/null
86 @@ -1,15 +0,0 @@
87 -VIA/Wondermedia VT8500 EHCI Controller
88 ------------------------------------------------------
89 -
90 -Required properties:
91 -- compatible : "via,vt8500-ehci"
92 -- reg : Should contain 1 register ranges(address and length)
93 -- interrupts : ehci controller interrupt
94 -
95 -Example:
96 -
97 -       ehci@d8007900 {
98 -               compatible = "via,vt8500-ehci";
99 -               reg = <0xd8007900 0x200>;
100 -               interrupts = <43>;
101 -       };
102 diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
103 deleted file mode 100644
104 index 5fb8fd6..0000000
105 --- a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
106 +++ /dev/null
107 @@ -1,12 +0,0 @@
108 -VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
109 -
110 -Required properties:
111 - - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
112 - - reg: Address range of the ehci registers. size should be 0x200
113 - - interrupts: Should contain the ehci interrupt.
114 -
115 -usb: ehci@D8007100 {
116 -       compatible = "wm,prizm-ehci", "usb-ehci";
117 -       reg = <0xD8007100 0x200>;
118 -       interrupts = <1>;
119 -};
120 diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
121 index a9707da..e28cbe0 100644
122 --- a/drivers/usb/host/Kconfig
123 +++ b/drivers/usb/host/Kconfig
124 @@ -255,6 +255,7 @@ config USB_EHCI_ATH79
125  
126  config USB_EHCI_HCD_PLATFORM
127         tristate "Generic EHCI driver for a platform device"
128 +       depends on !PPC_OF
129         default n
130         ---help---
131           Adds an EHCI host driver for a generic platform device, which
132 diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
133 index 01536cf..5ebd0b7 100644
134 --- a/drivers/usb/host/ehci-platform.c
135 +++ b/drivers/usb/host/ehci-platform.c
136 @@ -3,6 +3,7 @@
137   *
138   * Copyright 2007 Steven Brown <sbrown@cortland.com>
139   * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
140 + * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
141   *
142   * Derived from the ohci-ssb driver
143   * Copyright 2007 Michael Buesch <m@bues.ch>
144 @@ -18,6 +19,7 @@
145   *
146   * Licensed under the GNU/GPL. See COPYING for details.
147   */
148 +#include <linux/clk.h>
149  #include <linux/dma-mapping.h>
150  #include <linux/err.h>
151  #include <linux/kernel.h>
152 @@ -25,6 +27,7 @@
153  #include <linux/io.h>
154  #include <linux/module.h>
155  #include <linux/of.h>
156 +#include <linux/phy/phy.h>
157  #include <linux/platform_device.h>
158  #include <linux/usb.h>
159  #include <linux/usb/hcd.h>
160 @@ -33,6 +36,13 @@
161  #include "ehci.h"
162  
163  #define DRIVER_DESC "EHCI generic platform driver"
164 +#define EHCI_MAX_CLKS 3
165 +#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
166 +
167 +struct ehci_platform_priv {
168 +       struct clk *clks[EHCI_MAX_CLKS];
169 +       struct phy *phy;
170 +};
171  
172  static const char hcd_name[] = "ehci-platform";
173  
174 @@ -64,38 +74,90 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
175         return 0;
176  }
177  
178 +static int ehci_platform_power_on(struct platform_device *dev)
179 +{
180 +       struct usb_hcd *hcd = platform_get_drvdata(dev);
181 +       struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
182 +       int clk, ret;
183 +
184 +       for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
185 +               ret = clk_prepare_enable(priv->clks[clk]);
186 +               if (ret)
187 +                       goto err_disable_clks;
188 +       }
189 +
190 +       if (priv->phy) {
191 +               ret = phy_init(priv->phy);
192 +               if (ret)
193 +                       goto err_disable_clks;
194 +
195 +               ret = phy_power_on(priv->phy);
196 +               if (ret)
197 +                       goto err_exit_phy;
198 +       }
199 +
200 +       return 0;
201 +
202 +err_exit_phy:
203 +       phy_exit(priv->phy);
204 +err_disable_clks:
205 +       while (--clk >= 0)
206 +               clk_disable_unprepare(priv->clks[clk]);
207 +
208 +       return ret;
209 +}
210 +
211 +static void ehci_platform_power_off(struct platform_device *dev)
212 +{
213 +       struct usb_hcd *hcd = platform_get_drvdata(dev);
214 +       struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
215 +       int clk;
216 +
217 +       if (priv->phy) {
218 +               phy_power_off(priv->phy);
219 +               phy_exit(priv->phy);
220 +       }
221 +
222 +       for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
223 +               if (priv->clks[clk])
224 +                       clk_disable_unprepare(priv->clks[clk]);
225 +}
226 +
227  static struct hc_driver __read_mostly ehci_platform_hc_driver;
228  
229  static const struct ehci_driver_overrides platform_overrides __initconst = {
230 -       .reset =        ehci_platform_reset,
231 +       .reset =                ehci_platform_reset,
232 +       .extra_priv_size =      sizeof(struct ehci_platform_priv),
233  };
234  
235 -static struct usb_ehci_pdata ehci_platform_defaults;
236 +static struct usb_ehci_pdata ehci_platform_defaults = {
237 +       .power_on =             ehci_platform_power_on,
238 +       .power_suspend =        ehci_platform_power_off,
239 +       .power_off =            ehci_platform_power_off,
240 +};
241  
242  static int ehci_platform_probe(struct platform_device *dev)
243  {
244         struct usb_hcd *hcd;
245         struct resource *res_mem;
246 -       struct usb_ehci_pdata *pdata;
247 -       int irq;
248 -       int err;
249 +       struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
250 +       struct ehci_platform_priv *priv;
251 +       int err, irq, clk = 0;
252  
253         if (usb_disabled())
254                 return -ENODEV;
255  
256         /*
257 -        * use reasonable defaults so platforms don't have to provide these.
258 -        * with DT probing on ARM, none of these are set.
259 +        * Use reasonable defaults so platforms don't have to provide these
260 +        * with DT probing on ARM.
261          */
262 -       if (!dev_get_platdata(&dev->dev))
263 -               dev->dev.platform_data = &ehci_platform_defaults;
264 +       if (!pdata)
265 +               pdata = &ehci_platform_defaults;
266  
267         err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
268         if (err)
269                 return err;
270  
271 -       pdata = dev_get_platdata(&dev->dev);
272 -
273         irq = platform_get_irq(dev, 0);
274         if (irq < 0) {
275                 dev_err(&dev->dev, "no irq provided");
276 @@ -107,17 +169,40 @@ static int ehci_platform_probe(struct platform_device *dev)
277                 return -ENXIO;
278         }
279  
280 +       hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
281 +                            dev_name(&dev->dev));
282 +       if (!hcd)
283 +               return -ENOMEM;
284 +
285 +       platform_set_drvdata(dev, hcd);
286 +       dev->dev.platform_data = pdata;
287 +       priv = hcd_to_ehci_priv(hcd);
288 +
289 +       if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
290 +               priv->phy = devm_phy_get(&dev->dev, "usb");
291 +               if (IS_ERR(priv->phy)) {
292 +                       err = PTR_ERR(priv->phy);
293 +                       if (err == -EPROBE_DEFER)
294 +                               goto err_put_hcd;
295 +                       priv->phy = NULL;
296 +               }
297 +
298 +               for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
299 +                       priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
300 +                       if (IS_ERR(priv->clks[clk])) {
301 +                               err = PTR_ERR(priv->clks[clk]);
302 +                               if (err == -EPROBE_DEFER)
303 +                                       goto err_put_clks;
304 +                               priv->clks[clk] = NULL;
305 +                               break;
306 +                       }
307 +               }
308 +       }
309 +
310         if (pdata->power_on) {
311                 err = pdata->power_on(dev);
312                 if (err < 0)
313 -                       return err;
314 -       }
315 -
316 -       hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
317 -                            dev_name(&dev->dev));
318 -       if (!hcd) {
319 -               err = -ENOMEM;
320 -               goto err_power;
321 +                       goto err_put_clks;
322         }
323  
324         hcd->rsrc_start = res_mem->start;
325 @@ -126,22 +211,28 @@ static int ehci_platform_probe(struct platform_device *dev)
326         hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
327         if (IS_ERR(hcd->regs)) {
328                 err = PTR_ERR(hcd->regs);
329 -               goto err_put_hcd;
330 +               goto err_power;
331         }
332         err = usb_add_hcd(hcd, irq, IRQF_SHARED);
333         if (err)
334 -               goto err_put_hcd;
335 +               goto err_power;
336  
337         device_wakeup_enable(hcd->self.controller);
338         platform_set_drvdata(dev, hcd);
339  
340         return err;
341  
342 -err_put_hcd:
343 -       usb_put_hcd(hcd);
344  err_power:
345         if (pdata->power_off)
346                 pdata->power_off(dev);
347 +err_put_clks:
348 +       while (--clk >= 0)
349 +               clk_put(priv->clks[clk]);
350 +err_put_hcd:
351 +       if (pdata == &ehci_platform_defaults)
352 +               dev->dev.platform_data = NULL;
353 +
354 +       usb_put_hcd(hcd);
355  
356         return err;
357  }
358 @@ -150,13 +241,19 @@ static int ehci_platform_remove(struct platform_device *dev)
359  {
360         struct usb_hcd *hcd = platform_get_drvdata(dev);
361         struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
362 +       struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
363 +       int clk;
364  
365         usb_remove_hcd(hcd);
366 -       usb_put_hcd(hcd);
367  
368         if (pdata->power_off)
369                 pdata->power_off(dev);
370  
371 +       for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
372 +               clk_put(priv->clks[clk]);
373 +
374 +       usb_put_hcd(hcd);
375 +
376         if (pdata == &ehci_platform_defaults)
377                 dev->dev.platform_data = NULL;
378  
379 @@ -207,8 +304,10 @@ static int ehci_platform_resume(struct device *dev)
380  static const struct of_device_id vt8500_ehci_ids[] = {
381         { .compatible = "via,vt8500-ehci", },
382         { .compatible = "wm,prizm-ehci", },
383 +       { .compatible = "usb-ehci", },
384         {}
385  };
386 +MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
387  
388  static const struct platform_device_id ehci_platform_table[] = {
389         { "ehci-platform", 0 },
390 -- 
391 1.8.5.5
392