aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-s5p.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-s5p.c')
-rw-r--r--drivers/usb/host/ehci-s5p.c135
1 files changed, 54 insertions, 81 deletions
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index c474cec064e4..9d8f1dd57cb3 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -13,7 +13,9 @@
13 */ 13 */
14 14
15#include <linux/clk.h> 15#include <linux/clk.h>
16#include <linux/of.h>
16#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/of_gpio.h>
17#include <plat/ehci.h> 19#include <plat/ehci.h>
18#include <plat/usb-phy.h> 20#include <plat/usb-phy.h>
19 21
@@ -40,7 +42,7 @@ static const struct hc_driver s5p_ehci_hc_driver = {
40 .irq = ehci_irq, 42 .irq = ehci_irq,
41 .flags = HCD_MEMORY | HCD_USB2, 43 .flags = HCD_MEMORY | HCD_USB2,
42 44
43 .reset = ehci_init, 45 .reset = ehci_setup,
44 .start = ehci_run, 46 .start = ehci_run,
45 .stop = ehci_stop, 47 .stop = ehci_stop,
46 .shutdown = ehci_shutdown, 48 .shutdown = ehci_shutdown,
@@ -63,6 +65,26 @@ static const struct hc_driver s5p_ehci_hc_driver = {
63 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 65 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
64}; 66};
65 67
68static void s5p_setup_vbus_gpio(struct platform_device *pdev)
69{
70 int err;
71 int gpio;
72
73 if (!pdev->dev.of_node)
74 return;
75
76 gpio = of_get_named_gpio(pdev->dev.of_node,
77 "samsung,vbus-gpio", 0);
78 if (!gpio_is_valid(gpio))
79 return;
80
81 err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio");
82 if (err)
83 dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
84}
85
86static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
87
66static int __devinit s5p_ehci_probe(struct platform_device *pdev) 88static int __devinit s5p_ehci_probe(struct platform_device *pdev)
67{ 89{
68 struct s5p_ehci_platdata *pdata; 90 struct s5p_ehci_platdata *pdata;
@@ -79,7 +101,20 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
79 return -EINVAL; 101 return -EINVAL;
80 } 102 }
81 103
82 s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL); 104 /*
105 * Right now device-tree probed devices don't get dma_mask set.
106 * Since shared usb code relies on it, set it here for now.
107 * Once we move to full device tree support this will vanish off.
108 */
109 if (!pdev->dev.dma_mask)
110 pdev->dev.dma_mask = &ehci_s5p_dma_mask;
111 if (!pdev->dev.coherent_dma_mask)
112 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
113
114 s5p_setup_vbus_gpio(pdev);
115
116 s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd),
117 GFP_KERNEL);
83 if (!s5p_ehci) 118 if (!s5p_ehci)
84 return -ENOMEM; 119 return -ENOMEM;
85 120
@@ -89,8 +124,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
89 dev_name(&pdev->dev)); 124 dev_name(&pdev->dev));
90 if (!hcd) { 125 if (!hcd) {
91 dev_err(&pdev->dev, "Unable to create HCD\n"); 126 dev_err(&pdev->dev, "Unable to create HCD\n");
92 err = -ENOMEM; 127 return -ENOMEM;
93 goto fail_hcd;
94 } 128 }
95 129
96 s5p_ehci->hcd = hcd; 130 s5p_ehci->hcd = hcd;
@@ -115,7 +149,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
115 149
116 hcd->rsrc_start = res->start; 150 hcd->rsrc_start = res->start;
117 hcd->rsrc_len = resource_size(res); 151 hcd->rsrc_len = resource_size(res);
118 hcd->regs = ioremap(res->start, resource_size(res)); 152 hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
119 if (!hcd->regs) { 153 if (!hcd->regs) {
120 dev_err(&pdev->dev, "Failed to remap I/O memory\n"); 154 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
121 err = -ENOMEM; 155 err = -ENOMEM;
@@ -126,7 +160,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
126 if (!irq) { 160 if (!irq) {
127 dev_err(&pdev->dev, "Failed to get IRQ\n"); 161 dev_err(&pdev->dev, "Failed to get IRQ\n");
128 err = -ENODEV; 162 err = -ENODEV;
129 goto fail; 163 goto fail_io;
130 } 164 }
131 165
132 if (pdata->phy_init) 166 if (pdata->phy_init)
@@ -134,40 +168,26 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
134 168
135 ehci = hcd_to_ehci(hcd); 169 ehci = hcd_to_ehci(hcd);
136 ehci->caps = hcd->regs; 170 ehci->caps = hcd->regs;
137 ehci->regs = hcd->regs +
138 HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
139 171
140 /* DMA burst Enable */ 172 /* DMA burst Enable */
141 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); 173 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
142 174
143 dbg_hcs_params(ehci, "reset");
144 dbg_hcc_params(ehci, "reset");
145
146 /* cache this readonly data; minimize chip reads */
147 ehci->hcs_params = readl(&ehci->caps->hcs_params);
148
149 ehci_reset(ehci);
150
151 err = usb_add_hcd(hcd, irq, IRQF_SHARED); 175 err = usb_add_hcd(hcd, irq, IRQF_SHARED);
152 if (err) { 176 if (err) {
153 dev_err(&pdev->dev, "Failed to add USB HCD\n"); 177 dev_err(&pdev->dev, "Failed to add USB HCD\n");
154 goto fail; 178 goto fail_io;
155 } 179 }
156 180
157 platform_set_drvdata(pdev, s5p_ehci); 181 platform_set_drvdata(pdev, s5p_ehci);
158 182
159 return 0; 183 return 0;
160 184
161fail:
162 iounmap(hcd->regs);
163fail_io: 185fail_io:
164 clk_disable(s5p_ehci->clk); 186 clk_disable(s5p_ehci->clk);
165fail_clken: 187fail_clken:
166 clk_put(s5p_ehci->clk); 188 clk_put(s5p_ehci->clk);
167fail_clk: 189fail_clk:
168 usb_put_hcd(hcd); 190 usb_put_hcd(hcd);
169fail_hcd:
170 kfree(s5p_ehci);
171 return err; 191 return err;
172} 192}
173 193
@@ -182,13 +202,10 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev)
182 if (pdata && pdata->phy_exit) 202 if (pdata && pdata->phy_exit)
183 pdata->phy_exit(pdev, S5P_USB_PHY_HOST); 203 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
184 204
185 iounmap(hcd->regs);
186
187 clk_disable(s5p_ehci->clk); 205 clk_disable(s5p_ehci->clk);
188 clk_put(s5p_ehci->clk); 206 clk_put(s5p_ehci->clk);
189 207
190 usb_put_hcd(hcd); 208 usb_put_hcd(hcd);
191 kfree(s5p_ehci);
192 209
193 return 0; 210 return 0;
194} 211}
@@ -207,27 +224,12 @@ static int s5p_ehci_suspend(struct device *dev)
207{ 224{
208 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); 225 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
209 struct usb_hcd *hcd = s5p_ehci->hcd; 226 struct usb_hcd *hcd = s5p_ehci->hcd;
210 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 227 bool do_wakeup = device_may_wakeup(dev);
211 struct platform_device *pdev = to_platform_device(dev); 228 struct platform_device *pdev = to_platform_device(dev);
212 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; 229 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
213 unsigned long flags; 230 int rc;
214 int rc = 0;
215
216 if (time_before(jiffies, ehci->next_statechange))
217 msleep(20);
218
219 /*
220 * Root hub was already suspended. Disable irq emission and
221 * mark HW unaccessible. The PM and USB cores make sure that
222 * the root hub is either suspended or stopped.
223 */
224 ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
225 spin_lock_irqsave(&ehci->lock, flags);
226 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
227 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
228 231
229 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 232 rc = ehci_suspend(hcd, do_wakeup);
230 spin_unlock_irqrestore(&ehci->lock, flags);
231 233
232 if (pdata && pdata->phy_exit) 234 if (pdata && pdata->phy_exit)
233 pdata->phy_exit(pdev, S5P_USB_PHY_HOST); 235 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
@@ -241,7 +243,6 @@ static int s5p_ehci_resume(struct device *dev)
241{ 243{
242 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); 244 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
243 struct usb_hcd *hcd = s5p_ehci->hcd; 245 struct usb_hcd *hcd = s5p_ehci->hcd;
244 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
245 struct platform_device *pdev = to_platform_device(dev); 246 struct platform_device *pdev = to_platform_device(dev);
246 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; 247 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
247 248
@@ -253,44 +254,7 @@ static int s5p_ehci_resume(struct device *dev)
253 /* DMA burst Enable */ 254 /* DMA burst Enable */
254 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); 255 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
255 256
256 if (time_before(jiffies, ehci->next_statechange)) 257 ehci_resume(hcd, false);
257 msleep(100);
258
259 /* Mark hardware accessible again as we are out of D3 state by now */
260 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
261
262 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
263 int mask = INTR_MASK;
264
265 ehci_prepare_ports_for_controller_resume(ehci);
266 if (!hcd->self.root_hub->do_remote_wakeup)
267 mask &= ~STS_PCD;
268 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
269 ehci_readl(ehci, &ehci->regs->intr_enable);
270 return 0;
271 }
272
273 usb_root_hub_lost_power(hcd->self.root_hub);
274
275 (void) ehci_halt(ehci);
276 (void) ehci_reset(ehci);
277
278 /* emptying the schedule aborts any urbs */
279 spin_lock_irq(&ehci->lock);
280 if (ehci->reclaim)
281 end_unlink_async(ehci);
282 ehci_work(ehci);
283 spin_unlock_irq(&ehci->lock);
284
285 ehci_writel(ehci, ehci->command, &ehci->regs->command);
286 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
287 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
288
289 /* here we "know" root ports should always stay powered */
290 ehci_port_power(ehci, 1);
291
292 ehci->rh_state = EHCI_RH_SUSPENDED;
293
294 return 0; 258 return 0;
295} 259}
296#else 260#else
@@ -303,6 +267,14 @@ static const struct dev_pm_ops s5p_ehci_pm_ops = {
303 .resume = s5p_ehci_resume, 267 .resume = s5p_ehci_resume,
304}; 268};
305 269
270#ifdef CONFIG_OF
271static const struct of_device_id exynos_ehci_match[] = {
272 { .compatible = "samsung,exynos-ehci" },
273 {},
274};
275MODULE_DEVICE_TABLE(of, exynos_ehci_match);
276#endif
277
306static struct platform_driver s5p_ehci_driver = { 278static struct platform_driver s5p_ehci_driver = {
307 .probe = s5p_ehci_probe, 279 .probe = s5p_ehci_probe,
308 .remove = __devexit_p(s5p_ehci_remove), 280 .remove = __devexit_p(s5p_ehci_remove),
@@ -311,6 +283,7 @@ static struct platform_driver s5p_ehci_driver = {
311 .name = "s5p-ehci", 283 .name = "s5p-ehci",
312 .owner = THIS_MODULE, 284 .owner = THIS_MODULE,
313 .pm = &s5p_ehci_pm_ops, 285 .pm = &s5p_ehci_pm_ops,
286 .of_match_table = of_match_ptr(exynos_ehci_match),
314 } 287 }
315}; 288};
316 289