xref: /openbmc/linux/drivers/usb/musb/omap2430.c (revision 78c99ba1)
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/slab.h>
31 #include <linux/init.h>
32 #include <linux/list.h>
33 #include <linux/clk.h>
34 #include <linux/io.h>
35 
36 #include <asm/mach-types.h>
37 #include <mach/hardware.h>
38 #include <mach/mux.h>
39 
40 #include "musb_core.h"
41 #include "omap2430.h"
42 
43 #ifdef CONFIG_ARCH_OMAP3430
44 #define	get_cpu_rev()	2
45 #endif
46 
47 #define MUSB_TIMEOUT_A_WAIT_BCON	1100
48 
49 static struct timer_list musb_idle_timer;
50 
51 static void musb_do_idle(unsigned long _musb)
52 {
53 	struct musb	*musb = (void *)_musb;
54 	unsigned long	flags;
55 #ifdef CONFIG_USB_MUSB_HDRC_HCD
56 	u8	power;
57 #endif
58 	u8	devctl;
59 
60 	spin_lock_irqsave(&musb->lock, flags);
61 
62 	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
63 
64 	switch (musb->xceiv.state) {
65 	case OTG_STATE_A_WAIT_BCON:
66 		devctl &= ~MUSB_DEVCTL_SESSION;
67 		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
68 
69 		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
70 		if (devctl & MUSB_DEVCTL_BDEVICE) {
71 			musb->xceiv.state = OTG_STATE_B_IDLE;
72 			MUSB_DEV_MODE(musb);
73 		} else {
74 			musb->xceiv.state = OTG_STATE_A_IDLE;
75 			MUSB_HST_MODE(musb);
76 		}
77 		break;
78 #ifdef CONFIG_USB_MUSB_HDRC_HCD
79 	case OTG_STATE_A_SUSPEND:
80 		/* finish RESUME signaling? */
81 		if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
82 			power = musb_readb(musb->mregs, MUSB_POWER);
83 			power &= ~MUSB_POWER_RESUME;
84 			DBG(1, "root port resume stopped, power %02x\n", power);
85 			musb_writeb(musb->mregs, MUSB_POWER, power);
86 			musb->is_active = 1;
87 			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
88 						| MUSB_PORT_STAT_RESUME);
89 			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
90 			usb_hcd_poll_rh_status(musb_to_hcd(musb));
91 			/* NOTE: it might really be A_WAIT_BCON ... */
92 			musb->xceiv.state = OTG_STATE_A_HOST;
93 		}
94 		break;
95 #endif
96 #ifdef CONFIG_USB_MUSB_HDRC_HCD
97 	case OTG_STATE_A_HOST:
98 		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
99 		if (devctl &  MUSB_DEVCTL_BDEVICE)
100 			musb->xceiv.state = OTG_STATE_B_IDLE;
101 		else
102 			musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
103 #endif
104 	default:
105 		break;
106 	}
107 	spin_unlock_irqrestore(&musb->lock, flags);
108 }
109 
110 
111 void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
112 {
113 	unsigned long		default_timeout = jiffies + msecs_to_jiffies(3);
114 	static unsigned long	last_timer;
115 
116 	if (timeout == 0)
117 		timeout = default_timeout;
118 
119 	/* Never idle if active, or when VBUS timeout is not set as host */
120 	if (musb->is_active || ((musb->a_wait_bcon == 0)
121 			&& (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
122 		DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
123 		del_timer(&musb_idle_timer);
124 		last_timer = jiffies;
125 		return;
126 	}
127 
128 	if (time_after(last_timer, timeout)) {
129 		if (!timer_pending(&musb_idle_timer))
130 			last_timer = timeout;
131 		else {
132 			DBG(4, "Longer idle timer already pending, ignoring\n");
133 			return;
134 		}
135 	}
136 	last_timer = timeout;
137 
138 	DBG(4, "%s inactive, for idle timer for %lu ms\n",
139 		otg_state_string(musb),
140 		(unsigned long)jiffies_to_msecs(timeout - jiffies));
141 	mod_timer(&musb_idle_timer, timeout);
142 }
143 
144 void musb_platform_enable(struct musb *musb)
145 {
146 }
147 void musb_platform_disable(struct musb *musb)
148 {
149 }
150 static void omap_vbus_power(struct musb *musb, int is_on, int sleeping)
151 {
152 }
153 
154 static void omap_set_vbus(struct musb *musb, int is_on)
155 {
156 	u8		devctl;
157 	/* HDRC controls CPEN, but beware current surges during device
158 	 * connect.  They can trigger transient overcurrent conditions
159 	 * that must be ignored.
160 	 */
161 
162 	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
163 
164 	if (is_on) {
165 		musb->is_active = 1;
166 		musb->xceiv.default_a = 1;
167 		musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
168 		devctl |= MUSB_DEVCTL_SESSION;
169 
170 		MUSB_HST_MODE(musb);
171 	} else {
172 		musb->is_active = 0;
173 
174 		/* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
175 		 * jumping right to B_IDLE...
176 		 */
177 
178 		musb->xceiv.default_a = 0;
179 		musb->xceiv.state = OTG_STATE_B_IDLE;
180 		devctl &= ~MUSB_DEVCTL_SESSION;
181 
182 		MUSB_DEV_MODE(musb);
183 	}
184 	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
185 
186 	DBG(1, "VBUS %s, devctl %02x "
187 		/* otg %3x conf %08x prcm %08x */ "\n",
188 		otg_state_string(musb),
189 		musb_readb(musb->mregs, MUSB_DEVCTL));
190 }
191 static int omap_set_power(struct otg_transceiver *x, unsigned mA)
192 {
193 	return 0;
194 }
195 
196 static int musb_platform_resume(struct musb *musb);
197 
198 int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
199 {
200 	u8	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
201 
202 	devctl |= MUSB_DEVCTL_SESSION;
203 	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
204 
205 	switch (musb_mode) {
206 #ifdef CONFIG_USB_MUSB_HDRC_HCD
207 	case MUSB_HOST:
208 		otg_set_host(&musb->xceiv, musb->xceiv.host);
209 		break;
210 #endif
211 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
212 	case MUSB_PERIPHERAL:
213 		otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
214 		break;
215 #endif
216 #ifdef CONFIG_USB_MUSB_OTG
217 	case MUSB_OTG:
218 		break;
219 #endif
220 	default:
221 		return -EINVAL;
222 	}
223 	return 0;
224 }
225 
226 int __init musb_platform_init(struct musb *musb)
227 {
228 	u32 l;
229 
230 #if defined(CONFIG_ARCH_OMAP2430)
231 	omap_cfg_reg(AE5_2430_USB0HS_STP);
232 #endif
233 
234 	musb_platform_resume(musb);
235 
236 	l = omap_readl(OTG_SYSCONFIG);
237 	l &= ~ENABLEWAKEUP;	/* disable wakeup */
238 	l &= ~NOSTDBY;		/* remove possible nostdby */
239 	l |= SMARTSTDBY;	/* enable smart standby */
240 	l &= ~AUTOIDLE;		/* disable auto idle */
241 	l &= ~NOIDLE;		/* remove possible noidle */
242 	l |= SMARTIDLE;		/* enable smart idle */
243 	l |= AUTOIDLE;		/* enable auto idle */
244 	omap_writel(l, OTG_SYSCONFIG);
245 
246 	l = omap_readl(OTG_INTERFSEL);
247 	l |= ULPI_12PIN;
248 	omap_writel(l, OTG_INTERFSEL);
249 
250 	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
251 			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
252 			omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
253 			omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
254 			omap_readl(OTG_SIMENABLE));
255 
256 	omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
257 
258 	if (is_host_enabled(musb))
259 		musb->board_set_vbus = omap_set_vbus;
260 	if (is_peripheral_enabled(musb))
261 		musb->xceiv.set_power = omap_set_power;
262 	musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
263 
264 	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
265 
266 	return 0;
267 }
268 
269 int musb_platform_suspend(struct musb *musb)
270 {
271 	u32 l;
272 
273 	if (!musb->clock)
274 		return 0;
275 
276 	/* in any role */
277 	l = omap_readl(OTG_FORCESTDBY);
278 	l |= ENABLEFORCE;	/* enable MSTANDBY */
279 	omap_writel(l, OTG_FORCESTDBY);
280 
281 	l = omap_readl(OTG_SYSCONFIG);
282 	l |= ENABLEWAKEUP;	/* enable wakeup */
283 	omap_writel(l, OTG_SYSCONFIG);
284 
285 	if (musb->xceiv.set_suspend)
286 		musb->xceiv.set_suspend(&musb->xceiv, 1);
287 
288 	if (musb->set_clock)
289 		musb->set_clock(musb->clock, 0);
290 	else
291 		clk_disable(musb->clock);
292 
293 	return 0;
294 }
295 
296 static int musb_platform_resume(struct musb *musb)
297 {
298 	u32 l;
299 
300 	if (!musb->clock)
301 		return 0;
302 
303 	if (musb->xceiv.set_suspend)
304 		musb->xceiv.set_suspend(&musb->xceiv, 0);
305 
306 	if (musb->set_clock)
307 		musb->set_clock(musb->clock, 1);
308 	else
309 		clk_enable(musb->clock);
310 
311 	l = omap_readl(OTG_SYSCONFIG);
312 	l &= ~ENABLEWAKEUP;	/* disable wakeup */
313 	omap_writel(l, OTG_SYSCONFIG);
314 
315 	l = omap_readl(OTG_FORCESTDBY);
316 	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
317 	omap_writel(l, OTG_FORCESTDBY);
318 
319 	return 0;
320 }
321 
322 
323 int musb_platform_exit(struct musb *musb)
324 {
325 
326 	omap_vbus_power(musb, 0 /*off*/, 1);
327 
328 	musb_platform_suspend(musb);
329 
330 	clk_put(musb->clock);
331 	musb->clock = 0;
332 
333 	return 0;
334 }
335