summaryrefslogtreecommitdiff
path: root/drivers/usb/da8xx_usb.c
blob: 5dd5f123936de8cbb6fc4742bfff3b247f048162 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 * TI's DA8xx platform specific usb wrapper functions.
 *
 * Copyright (c) 2004 Texas Instruments
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
 *
 * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
 *
 */

#include <common.h>

#ifdef CONFIG_USB_DA8XX

#include "da8xx_usb.h"

/* extern functions */
extern void lpsc_on(unsigned int id);

/* Timeout for DA8xx usb module */
#define DA8XX_USB_TIMEOUT 0x3FFFF


/* This function writes to a 32-bit register of platform usb wrapper */
inline void pusb_writel( u32 offset , u32 value )
{
	*(volatile u32*)(DA8XX_USB0_BASE+offset) = value;
}

/* This function reads a 32-bit register of platform usb wrapper */
inline u32 pusb_readl(u32 offset)
{
	return(*(volatile u32*)(DA8XX_USB0_BASE+offset));
}

/* This function writes to a 16-bit register of platform musb core */
inline void musb_writew(u32 offset, u16 value)
{
	*(volatile u16*)(MENTOR_USB0_BASE+offset) = value;
}

/* This function writes to a 8-bit register of platform musb core */
inline void musb_writeb(u32 offset, u8 value)
{
	*(volatile u8*)(MENTOR_USB0_BASE+offset) = value;
}

/* This function reads a 16-bit register of platform usb wrapper */
inline u16 musb_readw(u32 offset)
{
	return(*(volatile u16*)(MENTOR_USB0_BASE + offset));
}

/* This function reads a 8-bit register of platform usb wrapper */
inline u8 musb_readb(u32 offset)
{
	return(*(volatile u8*)(MENTOR_USB0_BASE+offset));
}

/*
 * This function enables VBUS by driving the GPIO Bank4 Pin 15 high.
 */
static void enable_vbus(void)
{
	u32 value;

	/* configure GPIO bank4 pin 15 in output direction */
	value = *(volatile u32 *)GPIO_BANK4_REG_DIR_ADDR;
	value &= ~0x8000;
	*(volatile u32 *)GPIO_BANK4_REG_DIR_ADDR = value;

	/* set GPIO bank4 pin 15 high to drive VBUS */
	value = *(volatile u32 *)GPIO_BANK4_REG_SET_ADDR;
	value |= 0x8000;
	*(volatile u32 *)GPIO_BANK4_REG_SET_ADDR = value;
}

/*
 * Enable the usb0 phy. This initialization procedure is explained in
 * the DA8xx USB user guide document.
 */
static u8 phy_on( void )
{
	u32 timeout;
	u8	result = 1;

	/* write access keys */
	*(volatile u32 *)(KICK0) = 0x83e70b13;
	*(volatile u32 *)(KICK1) = 0x95a4f1e0;


#ifdef CONFIG_USE_PINMUX

	/* set PINMUX[7:4] = 1 */
	*(volatile u32 *)(PINMUX9) |= ( 1 << 4 );
	*(volatile u32 *)(PINMUX9) &= 0xFFFFFF7F;

#endif

	/* reset the usb controller */
	pusb_writel( DA8XX_USB_CTRL_REG , 0x1 );
	udelay( 5000 );

	/* enable and then disable the usb phy reset */
	*(volatile u32*)CFGCHIP2 |= 0x00008000;
	udelay( 5000 );
	*(volatile u32*)CFGCHIP2 &= 0xFFFF7FFF;
	udelay( 5000 );

	/* configure phy (refer to da8xx usb user guide use case section) */
	*(volatile u32*)CFGCHIP2 &= 0xFFFF9FFF;
	*(volatile u32*)CFGCHIP2 &= 0xFFFFFBFF;
	*(volatile u32*)CFGCHIP2 &= 0xFFFFFDFF;
	*(volatile u32*)CFGCHIP2 |= 0x00000100;
	*(volatile u32*)CFGCHIP2 |= 0x00000020;
	*(volatile u32*)CFGCHIP2 |= 0x00000010;
	*(volatile u32*)CFGCHIP2 |= 0x00000002;
	*(volatile u32*)CFGCHIP2 &= 0xFFFFE7FF;
	*(volatile u32*)CFGCHIP2 |= 0x00000800;

	*(volatile u32*)CFGCHIP2 &= 0xFFFF9FFF;
	*(volatile u32*)CFGCHIP2 |= 0x00002000;
	*(volatile u32*)CFGCHIP2 |= 0x00000040;

	/* wait until the usb phy pll locks */
	timeout = DA8XX_USB_TIMEOUT;
	do {
		timeout--;
		if (timeout == 0)
			break;
	}
	while(((*(volatile u32*)CFGCHIP2) & 0x00020000) == 0);

	/* disable register access by writing invalid keys */
	*(volatile u32 *)(0x01C14038) = 0x0;
	*(volatile u32 *)(0x01C1403C) = 0x0;

	if (timeout == 0)
		result = 0;

	return(result);
}

/*
 * Disable the usb phy
 */
static void phy_off(void)
{
	/* write access keys */
	*(volatile u32 *)(KICK0) =	0;
	*(volatile u32 *)(KICK1) =	0;

	/* powerdown the on-chip PHY and its oscillator */
	*(volatile u32*)(CFGCHIP2) = 0x8600;
}


/*
 * This function performs DA8xx platform specific initialization for usb0.
 */
int musb_platform_init(void)
{
	u32  revision;

	/* enable psc for usb2.0 */
	lpsc_on(33);

	/* enable usb vbus */
	enable_vbus();

	/* start the on-chip usb phy and its pll */
	if (phy_on() == 0)
		return(-1);

	/* reset the controller */
	pusb_writel(DA8XX_USB_CTRL_REG, 0x1);
	udelay(5000);

	/* Returns zero if e.g. not clocked */
	revision = pusb_readl(DA8XX_USB_VERSION_REG);
	if (revision == 0)
		return(-1);

	/* Disable all interrupts */
	pusb_writel(DA8XX_USB_INT_MASK_SET_REG, 0x01FF1F1F);
	return(0);
}


/*
 * This function performs DA8xx platform specific deinitialization for usb0.
 */
void musb_platform_deinit(void)
{
	/* Turn of the phy */
	phy_off();

	/* flush any interrupts */
	pusb_writel(DA8XX_USB_INT_MASK_CLR_REG, DA8XX_USB_USBINT_MASK|DA8XX_USB_TXINT_MASK|DA8XX_USB_RXINT_MASK);
	pusb_writel(DA8XX_USB_EOI_REG, 0);
}

#endif /* CONFIG_USB_DA8XX */