aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-02-07 10:36:41 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-07 17:24:24 -0500
commita4aeb2117571292f4e002c54b3f91e138722bf7a (patch)
tree7e3f103fa6724d947b62582426443e5eda277c4e
parentca52a17ba975dbf47e87c9bc63086aca0cf92806 (diff)
ehci-platform: Add support for clks and phy passed through devicetree
Currently ehci-platform is only used in combination with devicetree when used with some Via socs. By extending it to (optionally) get clks and a phy from devicetree, and enabling / disabling those on power_on / off, it can be used more generically. Specifically after this commit it can be used for the ehci controller on Allwinner sunxi SoCs. Since ehci-platform is intended to handle any generic enough non pci ehci device, add a "usb-ehci" compatibility string. There already is a usb-ehci device-tree bindings document, update this with clks and phy bindings info. Although actually quite generic so far the via,vt8500 compatibilty string had its own bindings document. Somehow we even ended up with 2 of them. Since these provide no extra information over the generic usb-ehci documentation, this patch removes them. The ehci-ppc-of.c driver also claims the usb-ehci compatibility string, even though it mostly is ibm,usb-ehci-440epx specific. ehci-platform.c is not needed on ppc platforms, so add a !PPC_OF dependency to it to avoid 2 drivers claiming the same compatibility string getting build on ppc. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ehci.txt25
-rw-r--r--Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt15
-rw-r--r--Documentation/devicetree/bindings/usb/vt8500-ehci.txt12
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/host/ehci-platform.c147
5 files changed, 142 insertions, 58 deletions
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index fa18612f757b..2c1aeebe12b7 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -7,13 +7,14 @@ Required properties:
7 (debug-port or other) can be also specified here, but only after 7 (debug-port or other) can be also specified here, but only after
8 definition of standard EHCI registers. 8 definition of standard EHCI registers.
9 - interrupts : one EHCI interrupt should be described here. 9 - interrupts : one EHCI interrupt should be described here.
10If device registers are implemented in big endian mode, the device 10
11node should have "big-endian-regs" property. 11Optional properties:
12If controller implementation operates with big endian descriptors, 12 - big-endian-regs : boolean, set this for hcds with big-endian registers
13"big-endian-desc" property should be specified. 13 - big-endian-desc : boolean, set this for hcds with big-endian descriptors
14If both big endian registers and descriptors are used by the controller 14 - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
15implementation, "big-endian" property can be specified instead of having 15 - clocks : a list of phandle + clock specifier pairs
16both "big-endian-regs" and "big-endian-desc". 16 - phys : phandle + phy specifier pair
17 - phy-names : "usb"
17 18
18Example (Sequoia 440EPx): 19Example (Sequoia 440EPx):
19 ehci@e0000300 { 20 ehci@e0000300 {
@@ -23,3 +24,13 @@ Example (Sequoia 440EPx):
23 reg = <0 e0000300 90 0 e0000390 70>; 24 reg = <0 e0000300 90 0 e0000390 70>;
24 big-endian; 25 big-endian;
25 }; 26 };
27
28Example (Allwinner sun4i A10 SoC):
29 ehci0: usb@01c14000 {
30 compatible = "allwinner,sun4i-a10-ehci", "usb-ehci";
31 reg = <0x01c14000 0x100>;
32 interrupts = <39>;
33 clocks = <&ahb_gates 1>;
34 phys = <&usbphy 1>;
35 phy-names = "usb";
36 };
diff --git a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
deleted file mode 100644
index 17b3ad1d97e7..000000000000
--- a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
+++ /dev/null
@@ -1,15 +0,0 @@
1VIA/Wondermedia VT8500 EHCI Controller
2-----------------------------------------------------
3
4Required properties:
5- compatible : "via,vt8500-ehci"
6- reg : Should contain 1 register ranges(address and length)
7- interrupts : ehci controller interrupt
8
9Example:
10
11 ehci@d8007900 {
12 compatible = "via,vt8500-ehci";
13 reg = <0xd8007900 0x200>;
14 interrupts = <43>;
15 };
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
deleted file mode 100644
index 5fb8fd6e250c..000000000000
--- a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
+++ /dev/null
@@ -1,12 +0,0 @@
1VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
2
3Required properties:
4 - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
5 - reg: Address range of the ehci registers. size should be 0x200
6 - interrupts: Should contain the ehci interrupt.
7
8usb: ehci@D8007100 {
9 compatible = "wm,prizm-ehci", "usb-ehci";
10 reg = <0xD8007100 0x200>;
11 interrupts = <1>;
12};
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index a9707da7da0b..e28cbe0e1f57 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -255,6 +255,7 @@ config USB_EHCI_ATH79
255 255
256config USB_EHCI_HCD_PLATFORM 256config USB_EHCI_HCD_PLATFORM
257 tristate "Generic EHCI driver for a platform device" 257 tristate "Generic EHCI driver for a platform device"
258 depends on !PPC_OF
258 default n 259 default n
259 ---help--- 260 ---help---
260 Adds an EHCI host driver for a generic platform device, which 261 Adds an EHCI host driver for a generic platform device, which
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 01536cfd361d..5ebd0b75b58e 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Steven Brown <sbrown@cortland.com> 4 * Copyright 2007 Steven Brown <sbrown@cortland.com>
5 * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> 5 * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
6 * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
6 * 7 *
7 * Derived from the ohci-ssb driver 8 * Derived from the ohci-ssb driver
8 * Copyright 2007 Michael Buesch <m@bues.ch> 9 * Copyright 2007 Michael Buesch <m@bues.ch>
@@ -18,6 +19,7 @@
18 * 19 *
19 * Licensed under the GNU/GPL. See COPYING for details. 20 * Licensed under the GNU/GPL. See COPYING for details.
20 */ 21 */
22#include <linux/clk.h>
21#include <linux/dma-mapping.h> 23#include <linux/dma-mapping.h>
22#include <linux/err.h> 24#include <linux/err.h>
23#include <linux/kernel.h> 25#include <linux/kernel.h>
@@ -25,6 +27,7 @@
25#include <linux/io.h> 27#include <linux/io.h>
26#include <linux/module.h> 28#include <linux/module.h>
27#include <linux/of.h> 29#include <linux/of.h>
30#include <linux/phy/phy.h>
28#include <linux/platform_device.h> 31#include <linux/platform_device.h>
29#include <linux/usb.h> 32#include <linux/usb.h>
30#include <linux/usb/hcd.h> 33#include <linux/usb/hcd.h>
@@ -33,6 +36,13 @@
33#include "ehci.h" 36#include "ehci.h"
34 37
35#define DRIVER_DESC "EHCI generic platform driver" 38#define DRIVER_DESC "EHCI generic platform driver"
39#define EHCI_MAX_CLKS 3
40#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
41
42struct ehci_platform_priv {
43 struct clk *clks[EHCI_MAX_CLKS];
44 struct phy *phy;
45};
36 46
37static const char hcd_name[] = "ehci-platform"; 47static const char hcd_name[] = "ehci-platform";
38 48
@@ -64,38 +74,90 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
64 return 0; 74 return 0;
65} 75}
66 76
77static int ehci_platform_power_on(struct platform_device *dev)
78{
79 struct usb_hcd *hcd = platform_get_drvdata(dev);
80 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
81 int clk, ret;
82
83 for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
84 ret = clk_prepare_enable(priv->clks[clk]);
85 if (ret)
86 goto err_disable_clks;
87 }
88
89 if (priv->phy) {
90 ret = phy_init(priv->phy);
91 if (ret)
92 goto err_disable_clks;
93
94 ret = phy_power_on(priv->phy);
95 if (ret)
96 goto err_exit_phy;
97 }
98
99 return 0;
100
101err_exit_phy:
102 phy_exit(priv->phy);
103err_disable_clks:
104 while (--clk >= 0)
105 clk_disable_unprepare(priv->clks[clk]);
106
107 return ret;
108}
109
110static void ehci_platform_power_off(struct platform_device *dev)
111{
112 struct usb_hcd *hcd = platform_get_drvdata(dev);
113 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
114 int clk;
115
116 if (priv->phy) {
117 phy_power_off(priv->phy);
118 phy_exit(priv->phy);
119 }
120
121 for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
122 if (priv->clks[clk])
123 clk_disable_unprepare(priv->clks[clk]);
124}
125
67static struct hc_driver __read_mostly ehci_platform_hc_driver; 126static struct hc_driver __read_mostly ehci_platform_hc_driver;
68 127
69static const struct ehci_driver_overrides platform_overrides __initconst = { 128static const struct ehci_driver_overrides platform_overrides __initconst = {
70 .reset = ehci_platform_reset, 129 .reset = ehci_platform_reset,
130 .extra_priv_size = sizeof(struct ehci_platform_priv),
71}; 131};
72 132
73static struct usb_ehci_pdata ehci_platform_defaults; 133static struct usb_ehci_pdata ehci_platform_defaults = {
134 .power_on = ehci_platform_power_on,
135 .power_suspend = ehci_platform_power_off,
136 .power_off = ehci_platform_power_off,
137};
74 138
75static int ehci_platform_probe(struct platform_device *dev) 139static int ehci_platform_probe(struct platform_device *dev)
76{ 140{
77 struct usb_hcd *hcd; 141 struct usb_hcd *hcd;
78 struct resource *res_mem; 142 struct resource *res_mem;
79 struct usb_ehci_pdata *pdata; 143 struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
80 int irq; 144 struct ehci_platform_priv *priv;
81 int err; 145 int err, irq, clk = 0;
82 146
83 if (usb_disabled()) 147 if (usb_disabled())
84 return -ENODEV; 148 return -ENODEV;
85 149
86 /* 150 /*
87 * use reasonable defaults so platforms don't have to provide these. 151 * Use reasonable defaults so platforms don't have to provide these
88 * with DT probing on ARM, none of these are set. 152 * with DT probing on ARM.
89 */ 153 */
90 if (!dev_get_platdata(&dev->dev)) 154 if (!pdata)
91 dev->dev.platform_data = &ehci_platform_defaults; 155 pdata = &ehci_platform_defaults;
92 156
93 err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); 157 err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
94 if (err) 158 if (err)
95 return err; 159 return err;
96 160
97 pdata = dev_get_platdata(&dev->dev);
98
99 irq = platform_get_irq(dev, 0); 161 irq = platform_get_irq(dev, 0);
100 if (irq < 0) { 162 if (irq < 0) {
101 dev_err(&dev->dev, "no irq provided"); 163 dev_err(&dev->dev, "no irq provided");
@@ -107,17 +169,40 @@ static int ehci_platform_probe(struct platform_device *dev)
107 return -ENXIO; 169 return -ENXIO;
108 } 170 }
109 171
172 hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
173 dev_name(&dev->dev));
174 if (!hcd)
175 return -ENOMEM;
176
177 platform_set_drvdata(dev, hcd);
178 dev->dev.platform_data = pdata;
179 priv = hcd_to_ehci_priv(hcd);
180
181 if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
182 priv->phy = devm_phy_get(&dev->dev, "usb");
183 if (IS_ERR(priv->phy)) {
184 err = PTR_ERR(priv->phy);
185 if (err == -EPROBE_DEFER)
186 goto err_put_hcd;
187 priv->phy = NULL;
188 }
189
190 for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
191 priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
192 if (IS_ERR(priv->clks[clk])) {
193 err = PTR_ERR(priv->clks[clk]);
194 if (err == -EPROBE_DEFER)
195 goto err_put_clks;
196 priv->clks[clk] = NULL;
197 break;
198 }
199 }
200 }
201
110 if (pdata->power_on) { 202 if (pdata->power_on) {
111 err = pdata->power_on(dev); 203 err = pdata->power_on(dev);
112 if (err < 0) 204 if (err < 0)
113 return err; 205 goto err_put_clks;
114 }
115
116 hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
117 dev_name(&dev->dev));
118 if (!hcd) {
119 err = -ENOMEM;
120 goto err_power;
121 } 206 }
122 207
123 hcd->rsrc_start = res_mem->start; 208 hcd->rsrc_start = res_mem->start;
@@ -126,22 +211,28 @@ static int ehci_platform_probe(struct platform_device *dev)
126 hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); 211 hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
127 if (IS_ERR(hcd->regs)) { 212 if (IS_ERR(hcd->regs)) {
128 err = PTR_ERR(hcd->regs); 213 err = PTR_ERR(hcd->regs);
129 goto err_put_hcd; 214 goto err_power;
130 } 215 }
131 err = usb_add_hcd(hcd, irq, IRQF_SHARED); 216 err = usb_add_hcd(hcd, irq, IRQF_SHARED);
132 if (err) 217 if (err)
133 goto err_put_hcd; 218 goto err_power;
134 219
135 device_wakeup_enable(hcd->self.controller); 220 device_wakeup_enable(hcd->self.controller);
136 platform_set_drvdata(dev, hcd); 221 platform_set_drvdata(dev, hcd);
137 222
138 return err; 223 return err;
139 224
140err_put_hcd:
141 usb_put_hcd(hcd);
142err_power: 225err_power:
143 if (pdata->power_off) 226 if (pdata->power_off)
144 pdata->power_off(dev); 227 pdata->power_off(dev);
228err_put_clks:
229 while (--clk >= 0)
230 clk_put(priv->clks[clk]);
231err_put_hcd:
232 if (pdata == &ehci_platform_defaults)
233 dev->dev.platform_data = NULL;
234
235 usb_put_hcd(hcd);
145 236
146 return err; 237 return err;
147} 238}
@@ -150,13 +241,19 @@ static int ehci_platform_remove(struct platform_device *dev)
150{ 241{
151 struct usb_hcd *hcd = platform_get_drvdata(dev); 242 struct usb_hcd *hcd = platform_get_drvdata(dev);
152 struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); 243 struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
244 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
245 int clk;
153 246
154 usb_remove_hcd(hcd); 247 usb_remove_hcd(hcd);
155 usb_put_hcd(hcd);
156 248
157 if (pdata->power_off) 249 if (pdata->power_off)
158 pdata->power_off(dev); 250 pdata->power_off(dev);
159 251
252 for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
253 clk_put(priv->clks[clk]);
254
255 usb_put_hcd(hcd);
256
160 if (pdata == &ehci_platform_defaults) 257 if (pdata == &ehci_platform_defaults)
161 dev->dev.platform_data = NULL; 258 dev->dev.platform_data = NULL;
162 259
@@ -207,8 +304,10 @@ static int ehci_platform_resume(struct device *dev)
207static const struct of_device_id vt8500_ehci_ids[] = { 304static const struct of_device_id vt8500_ehci_ids[] = {
208 { .compatible = "via,vt8500-ehci", }, 305 { .compatible = "via,vt8500-ehci", },
209 { .compatible = "wm,prizm-ehci", }, 306 { .compatible = "wm,prizm-ehci", },
307 { .compatible = "usb-ehci", },
210 {} 308 {}
211}; 309};
310MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
212 311
213static const struct platform_device_id ehci_platform_table[] = { 312static const struct platform_device_id ehci_platform_table[] = {
214 { "ehci-platform", 0 }, 313 { "ehci-platform", 0 },