]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/usb/musb-new/omap2430.c
Merge 'u-boot-atmel/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / usb / musb-new / omap2430.c
1 /*
2  * Copyright (C) 2005-2007 by Texas Instruments
3  * Some code has been taken from tusb6010.c
4  * Copyrights for that are attributable to:
5  * Copyright (C) 2006 Nokia Corporation
6  * Tony Lindgren <tony@atomide.com>
7  *
8  * This file is part of the Inventra Controller Driver for Linux.
9  *
10  * The Inventra Controller Driver for Linux is free software; you
11  * can redistribute it and/or modify it under the terms of the GNU
12  * General Public License version 2 as published by the Free Software
13  * Foundation.
14  *
15  * The Inventra Controller Driver for Linux is distributed in
16  * the hope that it will be useful, but WITHOUT ANY WARRANTY;
17  * without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19  * License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with The Inventra Controller Driver for Linux ; if not,
23  * write to the Free Software Foundation, Inc., 59 Temple Place,
24  * Suite 330, Boston, MA  02111-1307  USA
25  *
26  */
27 #define __UBOOT__
28 #ifndef __UBOOT__
29 #include <linux/module.h>
30 #include <linux/kernel.h>
31 #include <linux/sched.h>
32 #include <linux/init.h>
33 #include <linux/list.h>
34 #include <linux/io.h>
35 #include <linux/platform_device.h>
36 #include <linux/dma-mapping.h>
37 #include <linux/pm_runtime.h>
38 #include <linux/err.h>
39 #include <linux/usb/musb-omap.h>
40 #else
41 #include <common.h>
42 #include <asm/omap_musb.h>
43 #include <twl4030.h>
44 #include "linux-compat.h"
45 #endif
46
47 #include "musb_core.h"
48 #include "omap2430.h"
49
50 #ifndef __UBOOT__
51 struct omap2430_glue {
52         struct device           *dev;
53         struct platform_device  *musb;
54         enum omap_musb_vbus_id_status status;
55         struct work_struct      omap_musb_mailbox_work;
56 };
57 #define glue_to_musb(g)         platform_get_drvdata(g->musb)
58
59 struct omap2430_glue            *_glue;
60
61 static struct timer_list musb_idle_timer;
62
63 static void musb_do_idle(unsigned long _musb)
64 {
65         struct musb     *musb = (void *)_musb;
66         unsigned long   flags;
67         u8      power;
68         u8      devctl;
69
70         spin_lock_irqsave(&musb->lock, flags);
71
72         switch (musb->xceiv->state) {
73         case OTG_STATE_A_WAIT_BCON:
74
75                 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
76                 if (devctl & MUSB_DEVCTL_BDEVICE) {
77                         musb->xceiv->state = OTG_STATE_B_IDLE;
78                         MUSB_DEV_MODE(musb);
79                 } else {
80                         musb->xceiv->state = OTG_STATE_A_IDLE;
81                         MUSB_HST_MODE(musb);
82                 }
83                 break;
84         case OTG_STATE_A_SUSPEND:
85                 /* finish RESUME signaling? */
86                 if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
87                         power = musb_readb(musb->mregs, MUSB_POWER);
88                         power &= ~MUSB_POWER_RESUME;
89                         dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
90                         musb_writeb(musb->mregs, MUSB_POWER, power);
91                         musb->is_active = 1;
92                         musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
93                                                 | MUSB_PORT_STAT_RESUME);
94                         musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
95                         usb_hcd_poll_rh_status(musb_to_hcd(musb));
96                         /* NOTE: it might really be A_WAIT_BCON ... */
97                         musb->xceiv->state = OTG_STATE_A_HOST;
98                 }
99                 break;
100         case OTG_STATE_A_HOST:
101                 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
102                 if (devctl &  MUSB_DEVCTL_BDEVICE)
103                         musb->xceiv->state = OTG_STATE_B_IDLE;
104                 else
105                         musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
106         default:
107                 break;
108         }
109         spin_unlock_irqrestore(&musb->lock, flags);
110 }
111
112
113 static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
114 {
115         unsigned long           default_timeout = jiffies + msecs_to_jiffies(3);
116         static unsigned long    last_timer;
117
118         if (timeout == 0)
119                 timeout = default_timeout;
120
121         /* Never idle if active, or when VBUS timeout is not set as host */
122         if (musb->is_active || ((musb->a_wait_bcon == 0)
123                         && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
124                 dev_dbg(musb->controller, "%s active, deleting timer\n",
125                         otg_state_string(musb->xceiv->state));
126                 del_timer(&musb_idle_timer);
127                 last_timer = jiffies;
128                 return;
129         }
130
131         if (time_after(last_timer, timeout)) {
132                 if (!timer_pending(&musb_idle_timer))
133                         last_timer = timeout;
134                 else {
135                         dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
136                         return;
137                 }
138         }
139         last_timer = timeout;
140
141         dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
142                 otg_state_string(musb->xceiv->state),
143                 (unsigned long)jiffies_to_msecs(timeout - jiffies));
144         mod_timer(&musb_idle_timer, timeout);
145 }
146
147 static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
148 {
149         struct usb_otg  *otg = musb->xceiv->otg;
150         u8              devctl;
151         unsigned long timeout = jiffies + msecs_to_jiffies(1000);
152         int ret = 1;
153         /* HDRC controls CPEN, but beware current surges during device
154          * connect.  They can trigger transient overcurrent conditions
155          * that must be ignored.
156          */
157
158         devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
159
160         if (is_on) {
161                 if (musb->xceiv->state == OTG_STATE_A_IDLE) {
162                         /* start the session */
163                         devctl |= MUSB_DEVCTL_SESSION;
164                         musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
165                         /*
166                          * Wait for the musb to set as A device to enable the
167                          * VBUS
168                          */
169                         while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
170
171                                 cpu_relax();
172
173                                 if (time_after(jiffies, timeout)) {
174                                         dev_err(musb->controller,
175                                         "configured as A device timeout");
176                                         ret = -EINVAL;
177                                         break;
178                                 }
179                         }
180
181                         if (ret && otg->set_vbus)
182                                 otg_set_vbus(otg, 1);
183                 } else {
184                         musb->is_active = 1;
185                         otg->default_a = 1;
186                         musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
187                         devctl |= MUSB_DEVCTL_SESSION;
188                         MUSB_HST_MODE(musb);
189                 }
190         } else {
191                 musb->is_active = 0;
192
193                 /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
194                  * jumping right to B_IDLE...
195                  */
196
197                 otg->default_a = 0;
198                 musb->xceiv->state = OTG_STATE_B_IDLE;
199                 devctl &= ~MUSB_DEVCTL_SESSION;
200
201                 MUSB_DEV_MODE(musb);
202         }
203         musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
204
205         dev_dbg(musb->controller, "VBUS %s, devctl %02x "
206                 /* otg %3x conf %08x prcm %08x */ "\n",
207                 otg_state_string(musb->xceiv->state),
208                 musb_readb(musb->mregs, MUSB_DEVCTL));
209 }
210
211 static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
212 {
213         u8      devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
214
215         devctl |= MUSB_DEVCTL_SESSION;
216         musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
217
218         return 0;
219 }
220 #endif
221
222 static inline void omap2430_low_level_exit(struct musb *musb)
223 {
224         u32 l;
225
226         /* in any role */
227         l = musb_readl(musb->mregs, OTG_FORCESTDBY);
228         l |= ENABLEFORCE;       /* enable MSTANDBY */
229         musb_writel(musb->mregs, OTG_FORCESTDBY, l);
230 }
231
232 static inline void omap2430_low_level_init(struct musb *musb)
233 {
234         u32 l;
235
236         l = musb_readl(musb->mregs, OTG_FORCESTDBY);
237         l &= ~ENABLEFORCE;      /* disable MSTANDBY */
238         musb_writel(musb->mregs, OTG_FORCESTDBY, l);
239 }
240
241 #ifndef __UBOOT__
242 void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
243 {
244         struct omap2430_glue    *glue = _glue;
245         struct musb             *musb = glue_to_musb(glue);
246
247         glue->status = status;
248         if (!musb) {
249                 dev_err(glue->dev, "musb core is not yet ready\n");
250                 return;
251         }
252
253         schedule_work(&glue->omap_musb_mailbox_work);
254 }
255 EXPORT_SYMBOL_GPL(omap_musb_mailbox);
256
257 static void omap_musb_set_mailbox(struct omap2430_glue *glue)
258 {
259         struct musb *musb = glue_to_musb(glue);
260         struct device *dev = musb->controller;
261         struct musb_hdrc_platform_data *pdata = dev->platform_data;
262         struct omap_musb_board_data *data = pdata->board_data;
263         struct usb_otg *otg = musb->xceiv->otg;
264
265         switch (glue->status) {
266         case OMAP_MUSB_ID_GROUND:
267                 dev_dbg(dev, "ID GND\n");
268
269                 otg->default_a = true;
270                 musb->xceiv->state = OTG_STATE_A_IDLE;
271                 musb->xceiv->last_event = USB_EVENT_ID;
272                 if (!is_otg_enabled(musb) || musb->gadget_driver) {
273                         pm_runtime_get_sync(dev);
274                         usb_phy_init(musb->xceiv);
275                         omap2430_musb_set_vbus(musb, 1);
276                 }
277                 break;
278
279         case OMAP_MUSB_VBUS_VALID:
280                 dev_dbg(dev, "VBUS Connect\n");
281
282                 otg->default_a = false;
283                 musb->xceiv->state = OTG_STATE_B_IDLE;
284                 musb->xceiv->last_event = USB_EVENT_VBUS;
285                 if (musb->gadget_driver)
286                         pm_runtime_get_sync(dev);
287                 usb_phy_init(musb->xceiv);
288                 break;
289
290         case OMAP_MUSB_ID_FLOAT:
291         case OMAP_MUSB_VBUS_OFF:
292                 dev_dbg(dev, "VBUS Disconnect\n");
293
294                 musb->xceiv->last_event = USB_EVENT_NONE;
295                 if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
296                         if (musb->gadget_driver) {
297                                 pm_runtime_mark_last_busy(dev);
298                                 pm_runtime_put_autosuspend(dev);
299                         }
300
301                 if (data->interface_type == MUSB_INTERFACE_UTMI) {
302                         if (musb->xceiv->otg->set_vbus)
303                                 otg_set_vbus(musb->xceiv->otg, 0);
304                 }
305                 usb_phy_shutdown(musb->xceiv);
306                 break;
307         default:
308                 dev_dbg(dev, "ID float\n");
309         }
310 }
311
312
313 static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
314 {
315         struct omap2430_glue *glue = container_of(mailbox_work,
316                                 struct omap2430_glue, omap_musb_mailbox_work);
317         omap_musb_set_mailbox(glue);
318 }
319 #endif
320
321 static int omap2430_musb_init(struct musb *musb)
322 {
323         u32 l;
324         int status = 0;
325 #ifndef __UBOOT__
326         struct device *dev = musb->controller;
327         struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
328         struct musb_hdrc_platform_data *plat = dev->platform_data;
329         struct omap_musb_board_data *data = plat->board_data;
330 #else
331         struct omap_musb_board_data *data =
332                 (struct omap_musb_board_data *)musb->controller;
333 #endif
334
335
336 #ifndef __UBOOT__
337         /* We require some kind of external transceiver, hooked
338          * up through ULPI.  TWL4030-family PMICs include one,
339          * which needs a driver, drivers aren't always needed.
340          */
341         musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
342         if (IS_ERR_OR_NULL(musb->xceiv)) {
343                 pr_err("HS USB OTG: no transceiver configured\n");
344                 return -ENODEV;
345         }
346
347         status = pm_runtime_get_sync(dev);
348         if (status < 0) {
349                 dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
350                 goto err1;
351         }
352 #endif
353
354         l = musb_readl(musb->mregs, OTG_INTERFSEL);
355
356         if (data->interface_type == MUSB_INTERFACE_UTMI) {
357                 /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
358                 l &= ~ULPI_12PIN;       /* Disable ULPI */
359                 l |= UTMI_8BIT;         /* Enable UTMI  */
360         } else {
361                 l |= ULPI_12PIN;
362         }
363
364         musb_writel(musb->mregs, OTG_INTERFSEL, l);
365
366         pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
367                         "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
368                         musb_readl(musb->mregs, OTG_REVISION),
369                         musb_readl(musb->mregs, OTG_SYSCONFIG),
370                         musb_readl(musb->mregs, OTG_SYSSTATUS),
371                         musb_readl(musb->mregs, OTG_INTERFSEL),
372                         musb_readl(musb->mregs, OTG_SIMENABLE));
373
374 #ifndef __UBOOT__
375         setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
376
377         if (glue->status != OMAP_MUSB_UNKNOWN)
378                 omap_musb_set_mailbox(glue);
379
380         pm_runtime_put_noidle(musb->controller);
381 #endif
382         return 0;
383
384 err1:
385         return status;
386 }
387
388 static void omap2430_musb_enable(struct musb *musb)
389 {
390 #ifndef __UBOOT__
391         u8              devctl;
392         unsigned long timeout = jiffies + msecs_to_jiffies(1000);
393         struct device *dev = musb->controller;
394         struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
395         struct musb_hdrc_platform_data *pdata = dev->platform_data;
396         struct omap_musb_board_data *data = pdata->board_data;
397
398         switch (glue->status) {
399
400         case OMAP_MUSB_ID_GROUND:
401                 usb_phy_init(musb->xceiv);
402                 if (data->interface_type != MUSB_INTERFACE_UTMI)
403                         break;
404                 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
405                 /* start the session */
406                 devctl |= MUSB_DEVCTL_SESSION;
407                 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
408                 while (musb_readb(musb->mregs, MUSB_DEVCTL) &
409                                 MUSB_DEVCTL_BDEVICE) {
410                         cpu_relax();
411
412                         if (time_after(jiffies, timeout)) {
413                                 dev_err(dev, "configured as A device timeout");
414                                 break;
415                         }
416                 }
417                 break;
418
419         case OMAP_MUSB_VBUS_VALID:
420                 usb_phy_init(musb->xceiv);
421                 break;
422
423         default:
424                 break;
425         }
426 #else
427 #ifdef CONFIG_TWL4030_USB
428         if (twl4030_usb_ulpi_init()) {
429                 serial_printf("ERROR: %s Could not initialize PHY\n",
430                                 __PRETTY_FUNCTION__);
431         }
432 #endif
433 #endif
434 }
435
436 static void omap2430_musb_disable(struct musb *musb)
437 {
438 #ifndef __UBOOT__
439         struct device *dev = musb->controller;
440         struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
441
442         if (glue->status != OMAP_MUSB_UNKNOWN)
443                 usb_phy_shutdown(musb->xceiv);
444 #endif
445 }
446
447 static int omap2430_musb_exit(struct musb *musb)
448 {
449         del_timer_sync(&musb_idle_timer);
450
451         omap2430_low_level_exit(musb);
452
453         return 0;
454 }
455
456 #ifndef __UBOOT__
457 static const struct musb_platform_ops omap2430_ops = {
458 #else
459 const struct musb_platform_ops omap2430_ops = {
460 #endif
461         .init           = omap2430_musb_init,
462         .exit           = omap2430_musb_exit,
463
464 #ifndef __UBOOT__
465         .set_mode       = omap2430_musb_set_mode,
466         .try_idle       = omap2430_musb_try_idle,
467
468         .set_vbus       = omap2430_musb_set_vbus,
469 #endif
470
471         .enable         = omap2430_musb_enable,
472         .disable        = omap2430_musb_disable,
473 };
474
475 #ifndef __UBOOT__
476 static u64 omap2430_dmamask = DMA_BIT_MASK(32);
477
478 static int __devinit omap2430_probe(struct platform_device *pdev)
479 {
480         struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
481         struct platform_device          *musb;
482         struct omap2430_glue            *glue;
483         int                             ret = -ENOMEM;
484
485         glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
486         if (!glue) {
487                 dev_err(&pdev->dev, "failed to allocate glue context\n");
488                 goto err0;
489         }
490
491         musb = platform_device_alloc("musb-hdrc", -1);
492         if (!musb) {
493                 dev_err(&pdev->dev, "failed to allocate musb device\n");
494                 goto err0;
495         }
496
497         musb->dev.parent                = &pdev->dev;
498         musb->dev.dma_mask              = &omap2430_dmamask;
499         musb->dev.coherent_dma_mask     = omap2430_dmamask;
500
501         glue->dev                       = &pdev->dev;
502         glue->musb                      = musb;
503         glue->status                    = OMAP_MUSB_UNKNOWN;
504
505         pdata->platform_ops             = &omap2430_ops;
506
507         platform_set_drvdata(pdev, glue);
508
509         /*
510          * REVISIT if we ever have two instances of the wrapper, we will be
511          * in big trouble
512          */
513         _glue   = glue;
514
515         INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
516
517         ret = platform_device_add_resources(musb, pdev->resource,
518                         pdev->num_resources);
519         if (ret) {
520                 dev_err(&pdev->dev, "failed to add resources\n");
521                 goto err1;
522         }
523
524         ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
525         if (ret) {
526                 dev_err(&pdev->dev, "failed to add platform_data\n");
527                 goto err1;
528         }
529
530         pm_runtime_enable(&pdev->dev);
531
532         ret = platform_device_add(musb);
533         if (ret) {
534                 dev_err(&pdev->dev, "failed to register musb device\n");
535                 goto err1;
536         }
537
538         return 0;
539
540 err1:
541         platform_device_put(musb);
542
543 err0:
544         return ret;
545 }
546
547 static int __devexit omap2430_remove(struct platform_device *pdev)
548 {
549         struct omap2430_glue            *glue = platform_get_drvdata(pdev);
550
551         cancel_work_sync(&glue->omap_musb_mailbox_work);
552         platform_device_del(glue->musb);
553         platform_device_put(glue->musb);
554
555         return 0;
556 }
557
558 #ifdef CONFIG_PM
559
560 static int omap2430_runtime_suspend(struct device *dev)
561 {
562         struct omap2430_glue            *glue = dev_get_drvdata(dev);
563         struct musb                     *musb = glue_to_musb(glue);
564
565         if (musb) {
566                 musb->context.otg_interfsel = musb_readl(musb->mregs,
567                                 OTG_INTERFSEL);
568
569                 omap2430_low_level_exit(musb);
570                 usb_phy_set_suspend(musb->xceiv, 1);
571         }
572
573         return 0;
574 }
575
576 static int omap2430_runtime_resume(struct device *dev)
577 {
578         struct omap2430_glue            *glue = dev_get_drvdata(dev);
579         struct musb                     *musb = glue_to_musb(glue);
580
581         if (musb) {
582                 omap2430_low_level_init(musb);
583                 musb_writel(musb->mregs, OTG_INTERFSEL,
584                                 musb->context.otg_interfsel);
585
586                 usb_phy_set_suspend(musb->xceiv, 0);
587         }
588
589         return 0;
590 }
591
592 static struct dev_pm_ops omap2430_pm_ops = {
593         .runtime_suspend = omap2430_runtime_suspend,
594         .runtime_resume = omap2430_runtime_resume,
595 };
596
597 #define DEV_PM_OPS      (&omap2430_pm_ops)
598 #else
599 #define DEV_PM_OPS      NULL
600 #endif
601
602 static struct platform_driver omap2430_driver = {
603         .probe          = omap2430_probe,
604         .remove         = __devexit_p(omap2430_remove),
605         .driver         = {
606                 .name   = "musb-omap2430",
607                 .pm     = DEV_PM_OPS,
608         },
609 };
610
611 MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
612 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
613 MODULE_LICENSE("GPL v2");
614
615 static int __init omap2430_init(void)
616 {
617         return platform_driver_register(&omap2430_driver);
618 }
619 subsys_initcall(omap2430_init);
620
621 static void __exit omap2430_exit(void)
622 {
623         platform_driver_unregister(&omap2430_driver);
624 }
625 module_exit(omap2430_exit);
626 #endif