Merge branch 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / arch / arm / mach-omap2 / usb-musb.c
1 /*
2  * linux/arch/arm/mach-omap2/usb-musb.c
3  *
4  * This file will contain the board specific details for the
5  * MENTOR USB OTG controller on OMAP3430
6  *
7  * Copyright (C) 2007-2008 Texas Instruments
8  * Copyright (C) 2008 Nokia Corporation
9  * Author: Vikram Pandita
10  *
11  * Generalization by:
12  * Felipe Balbi <felipe.balbi@nokia.com>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18
19 #include <linux/types.h>
20 #include <linux/errno.h>
21 #include <linux/delay.h>
22 #include <linux/platform_device.h>
23 #include <linux/clk.h>
24 #include <linux/dma-mapping.h>
25 #include <linux/io.h>
26
27 #include <linux/usb/musb.h>
28
29 #include <mach/hardware.h>
30 #include <mach/irqs.h>
31 #include <mach/am35xx.h>
32 #include <plat/usb.h>
33 #include "control.h"
34
35 #if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
36
37 static void am35x_musb_reset(void)
38 {
39         u32     regval;
40
41         /* Reset the musb interface */
42         regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
43
44         regval |= AM35XX_USBOTGSS_SW_RST;
45         omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
46
47         regval &= ~AM35XX_USBOTGSS_SW_RST;
48         omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
49
50         regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
51 }
52
53 static void am35x_musb_phy_power(u8 on)
54 {
55         unsigned long timeout = jiffies + msecs_to_jiffies(100);
56         u32 devconf2;
57
58         if (on) {
59                 /*
60                  * Start the on-chip PHY and its PLL.
61                  */
62                 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
63
64                 devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
65                 devconf2 |= CONF2_PHY_PLLON;
66
67                 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
68
69                 pr_info(KERN_INFO "Waiting for PHY clock good...\n");
70                 while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
71                                 & CONF2_PHYCLKGD)) {
72                         cpu_relax();
73
74                         if (time_after(jiffies, timeout)) {
75                                 pr_err(KERN_ERR "musb PHY clock good timed out\n");
76                                 break;
77                         }
78                 }
79         } else {
80                 /*
81                  * Power down the on-chip PHY.
82                  */
83                 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
84
85                 devconf2 &= ~CONF2_PHY_PLLON;
86                 devconf2 |=  CONF2_PHYPWRDN | CONF2_OTGPWRDN;
87                 omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
88         }
89 }
90
91 static void am35x_musb_clear_irq(void)
92 {
93         u32 regval;
94
95         regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
96         regval |= AM35XX_USBOTGSS_INT_CLR;
97         omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
98         regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
99 }
100
101 static void am35x_musb_set_mode(u8 musb_mode)
102 {
103         u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
104
105         devconf2 &= ~CONF2_OTGMODE;
106         switch (musb_mode) {
107 #ifdef  CONFIG_USB_MUSB_HDRC_HCD
108         case MUSB_HOST:         /* Force VBUS valid, ID = 0 */
109                 devconf2 |= CONF2_FORCE_HOST;
110                 break;
111 #endif
112 #ifdef  CONFIG_USB_GADGET_MUSB_HDRC
113         case MUSB_PERIPHERAL:   /* Force VBUS valid, ID = 1 */
114                 devconf2 |= CONF2_FORCE_DEVICE;
115                 break;
116 #endif
117 #ifdef  CONFIG_USB_MUSB_OTG
118         case MUSB_OTG:          /* Don't override the VBUS/ID comparators */
119                 devconf2 |= CONF2_NO_OVERRIDE;
120                 break;
121 #endif
122         default:
123                 pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode);
124         }
125
126         omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
127 }
128
129 static struct resource musb_resources[] = {
130         [0] = { /* start and end set dynamically */
131                 .flags  = IORESOURCE_MEM,
132         },
133         [1] = { /* general IRQ */
134                 .start  = INT_243X_HS_USB_MC,
135                 .flags  = IORESOURCE_IRQ,
136                 .name   = "mc",
137         },
138         [2] = { /* DMA IRQ */
139                 .start  = INT_243X_HS_USB_DMA,
140                 .flags  = IORESOURCE_IRQ,
141                 .name   = "dma",
142         },
143 };
144
145 static struct musb_hdrc_config musb_config = {
146         .multipoint     = 1,
147         .dyn_fifo       = 1,
148         .num_eps        = 16,
149         .ram_bits       = 12,
150 };
151
152 static struct musb_hdrc_platform_data musb_plat = {
153 #ifdef CONFIG_USB_MUSB_OTG
154         .mode           = MUSB_OTG,
155 #elif defined(CONFIG_USB_MUSB_HDRC_HCD)
156         .mode           = MUSB_HOST,
157 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
158         .mode           = MUSB_PERIPHERAL,
159 #endif
160         /* .clock is set dynamically */
161         .config         = &musb_config,
162
163         /* REVISIT charge pump on TWL4030 can supply up to
164          * 100 mA ... but this value is board-specific, like
165          * "mode", and should be passed to usb_musb_init().
166          */
167         .power          = 50,                   /* up to 100 mA */
168 };
169
170 static u64 musb_dmamask = DMA_BIT_MASK(32);
171
172 static struct platform_device musb_device = {
173         .name           = "musb-omap2430",
174         .id             = -1,
175         .dev = {
176                 .dma_mask               = &musb_dmamask,
177                 .coherent_dma_mask      = DMA_BIT_MASK(32),
178                 .platform_data          = &musb_plat,
179         },
180         .num_resources  = ARRAY_SIZE(musb_resources),
181         .resource       = musb_resources,
182 };
183
184 void __init usb_musb_init(struct omap_musb_board_data *board_data)
185 {
186         if (cpu_is_omap243x()) {
187                 musb_resources[0].start = OMAP243X_HS_BASE;
188         } else if (cpu_is_omap3517() || cpu_is_omap3505()) {
189                 musb_device.name = "musb-am35x";
190                 musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE;
191                 musb_resources[1].start = INT_35XX_USBOTG_IRQ;
192                 board_data->set_phy_power = am35x_musb_phy_power;
193                 board_data->clear_irq = am35x_musb_clear_irq;
194                 board_data->set_mode = am35x_musb_set_mode;
195                 board_data->reset = am35x_musb_reset;
196         } else if (cpu_is_omap34xx()) {
197                 musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE;
198         } else if (cpu_is_omap44xx()) {
199                 musb_resources[0].start = OMAP44XX_HSUSB_OTG_BASE;
200                 musb_resources[1].start = OMAP44XX_IRQ_HS_USB_MC_N;
201                 musb_resources[2].start = OMAP44XX_IRQ_HS_USB_DMA_N;
202         }
203         musb_resources[0].end = musb_resources[0].start + SZ_4K - 1;
204
205         /*
206          * REVISIT: This line can be removed once all the platforms using
207          * musb_core.c have been converted to use use clkdev.
208          */
209         musb_plat.clock = "ick";
210         musb_plat.board_data = board_data;
211         musb_plat.power = board_data->power >> 1;
212         musb_plat.mode = board_data->mode;
213         musb_plat.extvbus = board_data->extvbus;
214
215         if (platform_device_register(&musb_device) < 0)
216                 printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
217 }
218
219 #else
220 void __init usb_musb_init(struct omap_musb_board_data *board_data)
221 {
222 }
223 #endif /* CONFIG_USB_MUSB_SOC */