]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/usb/host/ehci-omap.c
Merge tag 'mfd-3.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
[karo-tx-linux.git] / drivers / usb / host / ehci-omap.c
1 /*
2  * ehci-omap.c - driver for USBHOST on OMAP3/4 processors
3  *
4  * Bus Glue for the EHCI controllers in OMAP3/4
5  * Tested on several OMAP3 boards, and OMAP4 Pandaboard
6  *
7  * Copyright (C) 2007-2011 Texas Instruments, Inc.
8  *      Author: Vikram Pandita <vikram.pandita@ti.com>
9  *      Author: Anand Gadiyar <gadiyar@ti.com>
10  *      Author: Keshava Munegowda <keshava_mgowda@ti.com>
11  *
12  * Copyright (C) 2009 Nokia Corporation
13  *      Contact: Felipe Balbi <felipe.balbi@nokia.com>
14  *
15  * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
30  *
31  * TODO (last updated Feb 27, 2010):
32  *      - add kernel-doc
33  *      - enable AUTOIDLE
34  *      - add suspend/resume
35  *      - add HSIC and TLL support
36  *      - convert to use hwmod and runtime PM
37  */
38
39 #include <linux/platform_device.h>
40 #include <linux/slab.h>
41 #include <linux/usb/ulpi.h>
42 #include <plat/usb.h>
43 #include <linux/regulator/consumer.h>
44 #include <linux/pm_runtime.h>
45 #include <linux/gpio.h>
46 #include <linux/clk.h>
47
48 /* EHCI Register Set */
49 #define EHCI_INSNREG04                                  (0xA0)
50 #define EHCI_INSNREG04_DISABLE_UNSUSPEND                (1 << 5)
51 #define EHCI_INSNREG05_ULPI                             (0xA4)
52 #define EHCI_INSNREG05_ULPI_CONTROL_SHIFT               31
53 #define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT               24
54 #define EHCI_INSNREG05_ULPI_OPSEL_SHIFT                 22
55 #define EHCI_INSNREG05_ULPI_REGADD_SHIFT                16
56 #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT             8
57 #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT                0
58
59 /* Errata i693 */
60 static struct clk       *utmi_p1_fck;
61 static struct clk       *utmi_p2_fck;
62 static struct clk       *xclk60mhsp1_ck;
63 static struct clk       *xclk60mhsp2_ck;
64 static struct clk       *usbhost_p1_fck;
65 static struct clk       *usbhost_p2_fck;
66 static struct clk       *init_60m_fclk;
67
68 /*-------------------------------------------------------------------------*/
69
70 static const struct hc_driver ehci_omap_hc_driver;
71
72
73 static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
74 {
75         __raw_writel(val, base + reg);
76 }
77
78 static inline u32 ehci_read(void __iomem *base, u32 reg)
79 {
80         return __raw_readl(base + reg);
81 }
82
83 /* Erratum i693 workaround sequence */
84 static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
85 {
86         int ret = 0;
87
88         /* Switch to the internal 60 MHz clock */
89         ret = clk_set_parent(utmi_p1_fck, init_60m_fclk);
90         if (ret != 0)
91                 ehci_err(ehci, "init_60m_fclk set parent"
92                         "failed error:%d\n", ret);
93
94         ret = clk_set_parent(utmi_p2_fck, init_60m_fclk);
95         if (ret != 0)
96                 ehci_err(ehci, "init_60m_fclk set parent"
97                         "failed error:%d\n", ret);
98
99         clk_enable(usbhost_p1_fck);
100         clk_enable(usbhost_p2_fck);
101
102         /* Wait 1ms and switch back to the external clock */
103         mdelay(1);
104         ret = clk_set_parent(utmi_p1_fck, xclk60mhsp1_ck);
105         if (ret != 0)
106                 ehci_err(ehci, "xclk60mhsp1_ck set parent"
107                         "failed error:%d\n", ret);
108
109         ret = clk_set_parent(utmi_p2_fck, xclk60mhsp2_ck);
110         if (ret != 0)
111                 ehci_err(ehci, "xclk60mhsp2_ck set parent"
112                         "failed error:%d\n", ret);
113
114         clk_disable(usbhost_p1_fck);
115         clk_disable(usbhost_p2_fck);
116 }
117
118 static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
119 {
120         unsigned long timeout = jiffies + msecs_to_jiffies(1000);
121         unsigned reg = 0;
122
123         reg = ULPI_FUNC_CTRL_RESET
124                 /* FUNCTION_CTRL_SET register */
125                 | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
126                 /* Write */
127                 | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
128                 /* PORTn */
129                 | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
130                 /* start ULPI access*/
131                 | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
132
133         ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg);
134
135         /* Wait for ULPI access completion */
136         while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI)
137                         & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
138                 cpu_relax();
139
140                 if (time_after(jiffies, timeout)) {
141                         dev_dbg(hcd->self.controller,
142                                         "phy reset operation timed out\n");
143                         break;
144                 }
145         }
146 }
147
148 static int omap_ehci_init(struct usb_hcd *hcd)
149 {
150         struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
151         int                     rc;
152         struct ehci_hcd_omap_platform_data      *pdata;
153
154         pdata = hcd->self.controller->platform_data;
155
156         /* Hold PHYs in reset while initializing EHCI controller */
157         if (pdata->phy_reset) {
158                 if (gpio_is_valid(pdata->reset_gpio_port[0]))
159                         gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
160
161                 if (gpio_is_valid(pdata->reset_gpio_port[1]))
162                         gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
163
164                 /* Hold the PHY in RESET for enough time till DIR is high */
165                 udelay(10);
166         }
167
168         /* Soft reset the PHY using PHY reset command over ULPI */
169         if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
170                 omap_ehci_soft_phy_reset(hcd, 0);
171         if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
172                 omap_ehci_soft_phy_reset(hcd, 1);
173
174         /* we know this is the memory we want, no need to ioremap again */
175         ehci->caps = hcd->regs;
176
177         rc = ehci_setup(hcd);
178
179         if (pdata->phy_reset) {
180                 /* Hold the PHY in RESET for enough time till
181                  * PHY is settled and ready
182                  */
183                 udelay(10);
184
185                 if (gpio_is_valid(pdata->reset_gpio_port[0]))
186                         gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
187
188                 if (gpio_is_valid(pdata->reset_gpio_port[1]))
189                         gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
190         }
191
192         /* root ports should always stay powered */
193         ehci_port_power(ehci, 1);
194
195         return rc;
196 }
197
198 static int omap_ehci_hub_control(
199         struct usb_hcd  *hcd,
200         u16             typeReq,
201         u16             wValue,
202         u16             wIndex,
203         char            *buf,
204         u16             wLength
205 )
206 {
207         struct ehci_hcd *ehci = hcd_to_ehci(hcd);
208         u32 __iomem *status_reg = &ehci->regs->port_status[
209                                 (wIndex & 0xff) - 1];
210         u32             temp;
211         unsigned long   flags;
212         int             retval = 0;
213
214         spin_lock_irqsave(&ehci->lock, flags);
215
216         if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
217                 temp = ehci_readl(ehci, status_reg);
218                 if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
219                         retval = -EPIPE;
220                         goto done;
221                 }
222
223                 temp &= ~PORT_WKCONN_E;
224                 temp |= PORT_WKDISC_E | PORT_WKOC_E;
225                 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
226
227                 omap_ehci_erratum_i693(ehci);
228
229                 set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
230                 goto done;
231         }
232
233         spin_unlock_irqrestore(&ehci->lock, flags);
234
235         /* Handle the hub control events here */
236         return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
237 done:
238         spin_unlock_irqrestore(&ehci->lock, flags);
239         return retval;
240 }
241
242 static void disable_put_regulator(
243                 struct ehci_hcd_omap_platform_data *pdata)
244 {
245         int i;
246
247         for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
248                 if (pdata->regulator[i]) {
249                         regulator_disable(pdata->regulator[i]);
250                         regulator_put(pdata->regulator[i]);
251                 }
252         }
253 }
254
255 /* configure so an HC device and id are always provided */
256 /* always called with process context; sleeping is OK */
257
258 /**
259  * ehci_hcd_omap_probe - initialize TI-based HCDs
260  *
261  * Allocates basic resources for this USB host controller, and
262  * then invokes the start() method for the HCD associated with it
263  * through the hotplug entry's driver_data.
264  */
265 static int ehci_hcd_omap_probe(struct platform_device *pdev)
266 {
267         struct device                           *dev = &pdev->dev;
268         struct ehci_hcd_omap_platform_data      *pdata = dev->platform_data;
269         struct resource                         *res;
270         struct usb_hcd                          *hcd;
271         void __iomem                            *regs;
272         int                                     ret = -ENODEV;
273         int                                     irq;
274         int                                     i;
275         char                                    supply[7];
276
277         if (usb_disabled())
278                 return -ENODEV;
279
280         if (!dev->parent) {
281                 dev_err(dev, "Missing parent device\n");
282                 return -ENODEV;
283         }
284
285         irq = platform_get_irq_byname(pdev, "ehci-irq");
286         if (irq < 0) {
287                 dev_err(dev, "EHCI irq failed\n");
288                 return -ENODEV;
289         }
290
291         res =  platform_get_resource_byname(pdev,
292                                 IORESOURCE_MEM, "ehci");
293         if (!res) {
294                 dev_err(dev, "UHH EHCI get resource failed\n");
295                 return -ENODEV;
296         }
297
298         regs = ioremap(res->start, resource_size(res));
299         if (!regs) {
300                 dev_err(dev, "UHH EHCI ioremap failed\n");
301                 return -ENOMEM;
302         }
303
304         hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
305                         dev_name(dev));
306         if (!hcd) {
307                 dev_err(dev, "failed to create hcd with err %d\n", ret);
308                 ret = -ENOMEM;
309                 goto err_io;
310         }
311
312         hcd->rsrc_start = res->start;
313         hcd->rsrc_len = resource_size(res);
314         hcd->regs = regs;
315
316         /* get ehci regulator and enable */
317         for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
318                 if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
319                         pdata->regulator[i] = NULL;
320                         continue;
321                 }
322                 snprintf(supply, sizeof(supply), "hsusb%d", i);
323                 pdata->regulator[i] = regulator_get(dev, supply);
324                 if (IS_ERR(pdata->regulator[i])) {
325                         pdata->regulator[i] = NULL;
326                         dev_dbg(dev,
327                         "failed to get ehci port%d regulator\n", i);
328                 } else {
329                         regulator_enable(pdata->regulator[i]);
330                 }
331         }
332
333         pm_runtime_enable(dev);
334         pm_runtime_get_sync(dev);
335
336         /*
337          * An undocumented "feature" in the OMAP3 EHCI controller,
338          * causes suspended ports to be taken out of suspend when
339          * the USBCMD.Run/Stop bit is cleared (for example when
340          * we do ehci_bus_suspend).
341          * This breaks suspend-resume if the root-hub is allowed
342          * to suspend. Writing 1 to this undocumented register bit
343          * disables this feature and restores normal behavior.
344          */
345         ehci_write(regs, EHCI_INSNREG04,
346                                 EHCI_INSNREG04_DISABLE_UNSUSPEND);
347
348         ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
349         if (ret) {
350                 dev_err(dev, "failed to add hcd with err %d\n", ret);
351                 goto err_pm_runtime;
352         }
353
354         /* get clocks */
355         utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
356         if (IS_ERR(utmi_p1_fck)) {
357                 ret = PTR_ERR(utmi_p1_fck);
358                 dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
359                 goto err_add_hcd;
360         }
361
362         xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
363         if (IS_ERR(xclk60mhsp1_ck)) {
364                 ret = PTR_ERR(xclk60mhsp1_ck);
365                 dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
366                 goto err_utmi_p1_fck;
367         }
368
369         utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
370         if (IS_ERR(utmi_p2_fck)) {
371                 ret = PTR_ERR(utmi_p2_fck);
372                 dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
373                 goto err_xclk60mhsp1_ck;
374         }
375
376         xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
377         if (IS_ERR(xclk60mhsp2_ck)) {
378                 ret = PTR_ERR(xclk60mhsp2_ck);
379                 dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
380                 goto err_utmi_p2_fck;
381         }
382
383         usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
384         if (IS_ERR(usbhost_p1_fck)) {
385                 ret = PTR_ERR(usbhost_p1_fck);
386                 dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
387                 goto err_xclk60mhsp2_ck;
388         }
389
390         usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
391         if (IS_ERR(usbhost_p2_fck)) {
392                 ret = PTR_ERR(usbhost_p2_fck);
393                 dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
394                 goto err_usbhost_p1_fck;
395         }
396
397         init_60m_fclk = clk_get(dev, "init_60m_fclk");
398         if (IS_ERR(init_60m_fclk)) {
399                 ret = PTR_ERR(init_60m_fclk);
400                 dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
401                 goto err_usbhost_p2_fck;
402         }
403
404         return 0;
405
406 err_usbhost_p2_fck:
407         clk_put(usbhost_p2_fck);
408
409 err_usbhost_p1_fck:
410         clk_put(usbhost_p1_fck);
411
412 err_xclk60mhsp2_ck:
413         clk_put(xclk60mhsp2_ck);
414
415 err_utmi_p2_fck:
416         clk_put(utmi_p2_fck);
417
418 err_xclk60mhsp1_ck:
419         clk_put(xclk60mhsp1_ck);
420
421 err_utmi_p1_fck:
422         clk_put(utmi_p1_fck);
423
424 err_add_hcd:
425         usb_remove_hcd(hcd);
426
427 err_pm_runtime:
428         disable_put_regulator(pdata);
429         pm_runtime_put_sync(dev);
430         usb_put_hcd(hcd);
431
432 err_io:
433         iounmap(regs);
434         return ret;
435 }
436
437
438 /**
439  * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs
440  * @pdev: USB Host Controller being removed
441  *
442  * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking
443  * the HCD's stop() method.  It is always called from a thread
444  * context, normally "rmmod", "apmd", or something similar.
445  */
446 static int ehci_hcd_omap_remove(struct platform_device *pdev)
447 {
448         struct device *dev                              = &pdev->dev;
449         struct usb_hcd *hcd                             = dev_get_drvdata(dev);
450         struct ehci_hcd_omap_platform_data *pdata       = dev->platform_data;
451
452         usb_remove_hcd(hcd);
453         disable_put_regulator(dev->platform_data);
454         iounmap(hcd->regs);
455         usb_put_hcd(hcd);
456
457         clk_put(utmi_p1_fck);
458         clk_put(utmi_p2_fck);
459         clk_put(xclk60mhsp1_ck);
460         clk_put(xclk60mhsp2_ck);
461         clk_put(usbhost_p1_fck);
462         clk_put(usbhost_p2_fck);
463         clk_put(init_60m_fclk);
464
465         pm_runtime_put_sync(dev);
466         pm_runtime_disable(dev);
467
468         if (pdata->phy_reset) {
469                 if (gpio_is_valid(pdata->reset_gpio_port[0]))
470                         gpio_free(pdata->reset_gpio_port[0]);
471
472                 if (gpio_is_valid(pdata->reset_gpio_port[1]))
473                         gpio_free(pdata->reset_gpio_port[1]);
474         }
475         return 0;
476 }
477
478 static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
479 {
480         struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
481
482         if (hcd->driver->shutdown)
483                 hcd->driver->shutdown(hcd);
484 }
485
486 static struct platform_driver ehci_hcd_omap_driver = {
487         .probe                  = ehci_hcd_omap_probe,
488         .remove                 = ehci_hcd_omap_remove,
489         .shutdown               = ehci_hcd_omap_shutdown,
490         /*.suspend              = ehci_hcd_omap_suspend, */
491         /*.resume               = ehci_hcd_omap_resume, */
492         .driver = {
493                 .name           = "ehci-omap",
494         }
495 };
496
497 /*-------------------------------------------------------------------------*/
498
499 static const struct hc_driver ehci_omap_hc_driver = {
500         .description            = hcd_name,
501         .product_desc           = "OMAP-EHCI Host Controller",
502         .hcd_priv_size          = sizeof(struct ehci_hcd),
503
504         /*
505          * generic hardware linkage
506          */
507         .irq                    = ehci_irq,
508         .flags                  = HCD_MEMORY | HCD_USB2,
509
510         /*
511          * basic lifecycle operations
512          */
513         .reset                  = omap_ehci_init,
514         .start                  = ehci_run,
515         .stop                   = ehci_stop,
516         .shutdown               = ehci_shutdown,
517
518         /*
519          * managing i/o requests and associated device resources
520          */
521         .urb_enqueue            = ehci_urb_enqueue,
522         .urb_dequeue            = ehci_urb_dequeue,
523         .endpoint_disable       = ehci_endpoint_disable,
524         .endpoint_reset         = ehci_endpoint_reset,
525
526         /*
527          * scheduling support
528          */
529         .get_frame_number       = ehci_get_frame,
530
531         /*
532          * root hub support
533          */
534         .hub_status_data        = ehci_hub_status_data,
535         .hub_control            = omap_ehci_hub_control,
536         .bus_suspend            = ehci_bus_suspend,
537         .bus_resume             = ehci_bus_resume,
538
539         .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
540 };
541
542 MODULE_ALIAS("platform:omap-ehci");
543 MODULE_AUTHOR("Texas Instruments, Inc.");
544 MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
545