]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/usb/musb/omap2430.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/egtvedt...
[mv-sheeva.git] / drivers / usb / musb / 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 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/init.h>
31 #include <linux/list.h>
32 #include <linux/clk.h>
33 #include <linux/io.h>
34 #include <linux/platform_device.h>
35 #include <linux/dma-mapping.h>
36
37 #include "musb_core.h"
38 #include "omap2430.h"
39
40 struct omap2430_glue {
41         struct device           *dev;
42         struct platform_device  *musb;
43         struct clk              *clk;
44 };
45 #define glue_to_musb(g)         platform_get_drvdata(g->musb)
46
47 static struct timer_list musb_idle_timer;
48
49 static void musb_do_idle(unsigned long _musb)
50 {
51         struct musb     *musb = (void *)_musb;
52         unsigned long   flags;
53 #ifdef CONFIG_USB_MUSB_HDRC_HCD
54         u8      power;
55 #endif
56         u8      devctl;
57
58         spin_lock_irqsave(&musb->lock, flags);
59
60         switch (musb->xceiv->state) {
61         case OTG_STATE_A_WAIT_BCON:
62
63                 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
64                 if (devctl & MUSB_DEVCTL_BDEVICE) {
65                         musb->xceiv->state = OTG_STATE_B_IDLE;
66                         MUSB_DEV_MODE(musb);
67                 } else {
68                         musb->xceiv->state = OTG_STATE_A_IDLE;
69                         MUSB_HST_MODE(musb);
70                 }
71                 break;
72 #ifdef CONFIG_USB_MUSB_HDRC_HCD
73         case OTG_STATE_A_SUSPEND:
74                 /* finish RESUME signaling? */
75                 if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
76                         power = musb_readb(musb->mregs, MUSB_POWER);
77                         power &= ~MUSB_POWER_RESUME;
78                         DBG(1, "root port resume stopped, power %02x\n", power);
79                         musb_writeb(musb->mregs, MUSB_POWER, power);
80                         musb->is_active = 1;
81                         musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
82                                                 | MUSB_PORT_STAT_RESUME);
83                         musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
84                         usb_hcd_poll_rh_status(musb_to_hcd(musb));
85                         /* NOTE: it might really be A_WAIT_BCON ... */
86                         musb->xceiv->state = OTG_STATE_A_HOST;
87                 }
88                 break;
89 #endif
90 #ifdef CONFIG_USB_MUSB_HDRC_HCD
91         case OTG_STATE_A_HOST:
92                 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
93                 if (devctl &  MUSB_DEVCTL_BDEVICE)
94                         musb->xceiv->state = OTG_STATE_B_IDLE;
95                 else
96                         musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
97 #endif
98         default:
99                 break;
100         }
101         spin_unlock_irqrestore(&musb->lock, flags);
102 }
103
104
105 static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
106 {
107         unsigned long           default_timeout = jiffies + msecs_to_jiffies(3);
108         static unsigned long    last_timer;
109
110         if (timeout == 0)
111                 timeout = default_timeout;
112
113         /* Never idle if active, or when VBUS timeout is not set as host */
114         if (musb->is_active || ((musb->a_wait_bcon == 0)
115                         && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
116                 DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
117                 del_timer(&musb_idle_timer);
118                 last_timer = jiffies;
119                 return;
120         }
121
122         if (time_after(last_timer, timeout)) {
123                 if (!timer_pending(&musb_idle_timer))
124                         last_timer = timeout;
125                 else {
126                         DBG(4, "Longer idle timer already pending, ignoring\n");
127                         return;
128                 }
129         }
130         last_timer = timeout;
131
132         DBG(4, "%s inactive, for idle timer for %lu ms\n",
133                 otg_state_string(musb),
134                 (unsigned long)jiffies_to_msecs(timeout - jiffies));
135         mod_timer(&musb_idle_timer, timeout);
136 }
137
138 static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
139 {
140         u8              devctl;
141         unsigned long timeout = jiffies + msecs_to_jiffies(1000);
142         int ret = 1;
143         /* HDRC controls CPEN, but beware current surges during device
144          * connect.  They can trigger transient overcurrent conditions
145          * that must be ignored.
146          */
147
148         devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
149
150         if (is_on) {
151                 if (musb->xceiv->state == OTG_STATE_A_IDLE) {
152                         /* start the session */
153                         devctl |= MUSB_DEVCTL_SESSION;
154                         musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
155                         /*
156                          * Wait for the musb to set as A device to enable the
157                          * VBUS
158                          */
159                         while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
160
161                                 cpu_relax();
162
163                                 if (time_after(jiffies, timeout)) {
164                                         dev_err(musb->controller,
165                                         "configured as A device timeout");
166                                         ret = -EINVAL;
167                                         break;
168                                 }
169                         }
170
171                         if (ret && musb->xceiv->set_vbus)
172                                 otg_set_vbus(musb->xceiv, 1);
173                 } else {
174                         musb->is_active = 1;
175                         musb->xceiv->default_a = 1;
176                         musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
177                         devctl |= MUSB_DEVCTL_SESSION;
178                         MUSB_HST_MODE(musb);
179                 }
180         } else {
181                 musb->is_active = 0;
182
183                 /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
184                  * jumping right to B_IDLE...
185                  */
186
187                 musb->xceiv->default_a = 0;
188                 musb->xceiv->state = OTG_STATE_B_IDLE;
189                 devctl &= ~MUSB_DEVCTL_SESSION;
190
191                 MUSB_DEV_MODE(musb);
192         }
193         musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
194
195         DBG(1, "VBUS %s, devctl %02x "
196                 /* otg %3x conf %08x prcm %08x */ "\n",
197                 otg_state_string(musb),
198                 musb_readb(musb->mregs, MUSB_DEVCTL));
199 }
200
201 static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
202 {
203         u8      devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
204
205         devctl |= MUSB_DEVCTL_SESSION;
206         musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
207
208         return 0;
209 }
210
211 static inline void omap2430_low_level_exit(struct musb *musb)
212 {
213         u32 l;
214
215         /* in any role */
216         l = musb_readl(musb->mregs, OTG_FORCESTDBY);
217         l |= ENABLEFORCE;       /* enable MSTANDBY */
218         musb_writel(musb->mregs, OTG_FORCESTDBY, l);
219
220         l = musb_readl(musb->mregs, OTG_SYSCONFIG);
221         l |= ENABLEWAKEUP;      /* enable wakeup */
222         musb_writel(musb->mregs, OTG_SYSCONFIG, l);
223 }
224
225 static inline void omap2430_low_level_init(struct musb *musb)
226 {
227         u32 l;
228
229         l = musb_readl(musb->mregs, OTG_SYSCONFIG);
230         l &= ~ENABLEWAKEUP;     /* disable wakeup */
231         musb_writel(musb->mregs, OTG_SYSCONFIG, l);
232
233         l = musb_readl(musb->mregs, OTG_FORCESTDBY);
234         l &= ~ENABLEFORCE;      /* disable MSTANDBY */
235         musb_writel(musb->mregs, OTG_FORCESTDBY, l);
236 }
237
238 /* blocking notifier support */
239 static int musb_otg_notifications(struct notifier_block *nb,
240                 unsigned long event, void *unused)
241 {
242         struct musb     *musb = container_of(nb, struct musb, nb);
243         struct device *dev = musb->controller;
244         struct musb_hdrc_platform_data *pdata = dev->platform_data;
245         struct omap_musb_board_data *data = pdata->board_data;
246
247         switch (event) {
248         case USB_EVENT_ID:
249                 DBG(4, "ID GND\n");
250
251                 if (is_otg_enabled(musb)) {
252 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
253                         if (musb->gadget_driver) {
254                                 otg_init(musb->xceiv);
255
256                                 if (data->interface_type ==
257                                                 MUSB_INTERFACE_UTMI)
258                                         omap2430_musb_set_vbus(musb, 1);
259
260                         }
261 #endif
262                 } else {
263                         otg_init(musb->xceiv);
264                         if (data->interface_type ==
265                                         MUSB_INTERFACE_UTMI)
266                                 omap2430_musb_set_vbus(musb, 1);
267                 }
268                 break;
269
270         case USB_EVENT_VBUS:
271                 DBG(4, "VBUS Connect\n");
272
273                 otg_init(musb->xceiv);
274                 break;
275
276         case USB_EVENT_NONE:
277                 DBG(4, "VBUS Disconnect\n");
278
279                 if (data->interface_type == MUSB_INTERFACE_UTMI) {
280                         if (musb->xceiv->set_vbus)
281                                 otg_set_vbus(musb->xceiv, 0);
282                 }
283                 otg_shutdown(musb->xceiv);
284                 break;
285         default:
286                 DBG(4, "ID float\n");
287                 return NOTIFY_DONE;
288         }
289
290         return NOTIFY_OK;
291 }
292
293 static int omap2430_musb_init(struct musb *musb)
294 {
295         u32 l, status = 0;
296         struct device *dev = musb->controller;
297         struct musb_hdrc_platform_data *plat = dev->platform_data;
298         struct omap_musb_board_data *data = plat->board_data;
299
300         /* We require some kind of external transceiver, hooked
301          * up through ULPI.  TWL4030-family PMICs include one,
302          * which needs a driver, drivers aren't always needed.
303          */
304         musb->xceiv = otg_get_transceiver();
305         if (!musb->xceiv) {
306                 pr_err("HS USB OTG: no transceiver configured\n");
307                 return -ENODEV;
308         }
309
310         omap2430_low_level_init(musb);
311
312         l = musb_readl(musb->mregs, OTG_SYSCONFIG);
313         l &= ~ENABLEWAKEUP;     /* disable wakeup */
314         l &= ~NOSTDBY;          /* remove possible nostdby */
315         l |= SMARTSTDBY;        /* enable smart standby */
316         l &= ~AUTOIDLE;         /* disable auto idle */
317         l &= ~NOIDLE;           /* remove possible noidle */
318         l |= SMARTIDLE;         /* enable smart idle */
319         /*
320          * MUSB AUTOIDLE don't work in 3430.
321          * Workaround by Richard Woodruff/TI
322          */
323         if (!cpu_is_omap3430())
324                 l |= AUTOIDLE;          /* enable auto idle */
325         musb_writel(musb->mregs, OTG_SYSCONFIG, l);
326
327         l = musb_readl(musb->mregs, OTG_INTERFSEL);
328
329         if (data->interface_type == MUSB_INTERFACE_UTMI) {
330                 /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
331                 l &= ~ULPI_12PIN;       /* Disable ULPI */
332                 l |= UTMI_8BIT;         /* Enable UTMI  */
333         } else {
334                 l |= ULPI_12PIN;
335         }
336
337         musb_writel(musb->mregs, OTG_INTERFSEL, l);
338
339         pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
340                         "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
341                         musb_readl(musb->mregs, OTG_REVISION),
342                         musb_readl(musb->mregs, OTG_SYSCONFIG),
343                         musb_readl(musb->mregs, OTG_SYSSTATUS),
344                         musb_readl(musb->mregs, OTG_INTERFSEL),
345                         musb_readl(musb->mregs, OTG_SIMENABLE));
346
347         musb->nb.notifier_call = musb_otg_notifications;
348         status = otg_register_notifier(musb->xceiv, &musb->nb);
349
350         if (status)
351                 DBG(1, "notification register failed\n");
352
353         /* check whether cable is already connected */
354         if (musb->xceiv->state ==OTG_STATE_B_IDLE)
355                 musb_otg_notifications(&musb->nb, 1,
356                                         musb->xceiv->gadget);
357
358         setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
359
360         return 0;
361 }
362
363 static int omap2430_musb_exit(struct musb *musb)
364 {
365
366         omap2430_low_level_exit(musb);
367         otg_put_transceiver(musb->xceiv);
368
369         return 0;
370 }
371
372 static const struct musb_platform_ops omap2430_ops = {
373         .init           = omap2430_musb_init,
374         .exit           = omap2430_musb_exit,
375
376         .set_mode       = omap2430_musb_set_mode,
377         .try_idle       = omap2430_musb_try_idle,
378
379         .set_vbus       = omap2430_musb_set_vbus,
380 };
381
382 static u64 omap2430_dmamask = DMA_BIT_MASK(32);
383
384 static int __init omap2430_probe(struct platform_device *pdev)
385 {
386         struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
387         struct platform_device          *musb;
388         struct omap2430_glue            *glue;
389         struct clk                      *clk;
390
391         int                             ret = -ENOMEM;
392
393         glue = kzalloc(sizeof(*glue), GFP_KERNEL);
394         if (!glue) {
395                 dev_err(&pdev->dev, "failed to allocate glue context\n");
396                 goto err0;
397         }
398
399         musb = platform_device_alloc("musb-hdrc", -1);
400         if (!musb) {
401                 dev_err(&pdev->dev, "failed to allocate musb device\n");
402                 goto err1;
403         }
404
405         clk = clk_get(&pdev->dev, "ick");
406         if (IS_ERR(clk)) {
407                 dev_err(&pdev->dev, "failed to get clock\n");
408                 ret = PTR_ERR(clk);
409                 goto err2;
410         }
411
412         ret = clk_enable(clk);
413         if (ret) {
414                 dev_err(&pdev->dev, "failed to enable clock\n");
415                 goto err3;
416         }
417
418         musb->dev.parent                = &pdev->dev;
419         musb->dev.dma_mask              = &omap2430_dmamask;
420         musb->dev.coherent_dma_mask     = omap2430_dmamask;
421
422         glue->dev                       = &pdev->dev;
423         glue->musb                      = musb;
424         glue->clk                       = clk;
425
426         pdata->platform_ops             = &omap2430_ops;
427
428         platform_set_drvdata(pdev, glue);
429
430         ret = platform_device_add_resources(musb, pdev->resource,
431                         pdev->num_resources);
432         if (ret) {
433                 dev_err(&pdev->dev, "failed to add resources\n");
434                 goto err4;
435         }
436
437         ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
438         if (ret) {
439                 dev_err(&pdev->dev, "failed to add platform_data\n");
440                 goto err4;
441         }
442
443         ret = platform_device_add(musb);
444         if (ret) {
445                 dev_err(&pdev->dev, "failed to register musb device\n");
446                 goto err4;
447         }
448
449         return 0;
450
451 err4:
452         clk_disable(clk);
453
454 err3:
455         clk_put(clk);
456
457 err2:
458         platform_device_put(musb);
459
460 err1:
461         kfree(glue);
462
463 err0:
464         return ret;
465 }
466
467 static int __exit omap2430_remove(struct platform_device *pdev)
468 {
469         struct omap2430_glue            *glue = platform_get_drvdata(pdev);
470
471         platform_device_del(glue->musb);
472         platform_device_put(glue->musb);
473         clk_disable(glue->clk);
474         clk_put(glue->clk);
475         kfree(glue);
476
477         return 0;
478 }
479
480 #ifdef CONFIG_PM
481 static void omap2430_save_context(struct musb *musb)
482 {
483         musb->context.otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
484         musb->context.otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
485 }
486
487 static void omap2430_restore_context(struct musb *musb)
488 {
489         musb_writel(musb->mregs, OTG_SYSCONFIG, musb->context.otg_sysconfig);
490         musb_writel(musb->mregs, OTG_FORCESTDBY, musb->context.otg_forcestandby);
491 }
492
493 static int omap2430_suspend(struct device *dev)
494 {
495         struct omap2430_glue            *glue = dev_get_drvdata(dev);
496         struct musb                     *musb = glue_to_musb(glue);
497
498         omap2430_low_level_exit(musb);
499         otg_set_suspend(musb->xceiv, 1);
500         omap2430_save_context(musb);
501         clk_disable(glue->clk);
502
503         return 0;
504 }
505
506 static int omap2430_resume(struct device *dev)
507 {
508         struct omap2430_glue            *glue = dev_get_drvdata(dev);
509         struct musb                     *musb = glue_to_musb(glue);
510         int                             ret;
511
512         ret = clk_enable(glue->clk);
513         if (ret) {
514                 dev_err(dev, "faled to enable clock\n");
515                 return ret;
516         }
517
518         omap2430_low_level_init(musb);
519         omap2430_restore_context(musb);
520         otg_set_suspend(musb->xceiv, 0);
521
522         return 0;
523 }
524
525 static struct dev_pm_ops omap2430_pm_ops = {
526         .suspend        = omap2430_suspend,
527         .resume         = omap2430_resume,
528 };
529
530 #define DEV_PM_OPS      (&omap2430_pm_ops)
531 #else
532 #define DEV_PM_OPS      NULL
533 #endif
534
535 static struct platform_driver omap2430_driver = {
536         .remove         = __exit_p(omap2430_remove),
537         .driver         = {
538                 .name   = "musb-omap2430",
539                 .pm     = DEV_PM_OPS,
540         },
541 };
542
543 MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
544 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
545 MODULE_LICENSE("GPL v2");
546
547 static int __init omap2430_init(void)
548 {
549         return platform_driver_probe(&omap2430_driver, omap2430_probe);
550 }
551 subsys_initcall(omap2430_init);
552
553 static void __exit omap2430_exit(void)
554 {
555         platform_driver_unregister(&omap2430_driver);
556 }
557 module_exit(omap2430_exit);