Merge branch 'for-linus' of git://codeaurora.org/quic/kernel/davidb/linux-msm
[GitHub/mt8127/android_kernel_alcatel_ttab.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 if (cpu_is_omap44xx())
219 omap4430_phy_init(dev);
220
221 }
222
223 #else
224 void __init usb_musb_init(struct omap_musb_board_data *board_data)
225 {
226 }
227 #endif /* CONFIG_USB_MUSB_SOC */