[go: nahoru, domu]

blob: 587ffc7e70c9e884743437fb54a56ad92591d0ff [file] [log] [blame]
Erik Gilling8a715652011-03-22 14:00:56 -07001/*
2 * Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com
3 * MAX3421E USB host controller support
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the authors nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Erik Gilling51f17512011-02-17 20:39:36 -080030/* MAX3421E USB host controller support */
31
32#include "Max3421e.h"
33// #include "Max3421e_constants.h"
34
35static byte vbusState;
36
37/* Functions */
38
Erik Gillingbb9ab4b2011-02-17 20:41:12 -080039#define INT PE6
40#define INT_PORT PORTE
41#define INT_DDR DDRE
42#define INT_PIN PINE
43
44#define RST PJ2
45#define RST_PORT PORTJ
46#define RST_DDR DDRJ
47#define RST_PIN PINJ
48
49#define GPX PJ3
50#define GPX_PORT PORTJ
51#define GPX_DDR DDRJ
52#define GPX_PIN PINJ
53
54
55void MAX3421E::setRST(uint8_t val)
56{
57 if (val == LOW)
58 RST_PORT &= ~_BV(RST);
59 else
60 RST_PORT |= _BV(RST);
61}
62
63uint8_t MAX3421E::readINT(void)
64{
65 return INT_PIN & _BV(INT) ? HIGH : LOW;
66}
67
68uint8_t MAX3421E::readGPX(void)
69{
70 // return GPX_PIN & _BV(GPX) ? HIGH : LOW;
71 return LOW;
72}
73
74
75void MAX3421E::pinInit(void)
76{
77 INT_DDR &= ~_BV(INT);
78 RST_DDR |= _BV(RST);
79 digitalWrite(MAX_SS,HIGH);
80 setRST(HIGH);
81}
82
83
Erik Gilling51f17512011-02-17 20:39:36 -080084/* Constructor */
85MAX3421E::MAX3421E()
86{
87 spi_init();
Erik Gillingbb9ab4b2011-02-17 20:41:12 -080088 pinInit();
Erik Gilling51f17512011-02-17 20:39:36 -080089}
90
91byte MAX3421E::getVbusState( void )
92{
93 return( vbusState );
94}
95/* initialization */
96//void MAX3421E::init()
97//{
98// /* setup pins */
99// pinMode( MAX_INT, INPUT);
100// pinMode( MAX_GPX, INPUT );
101// pinMode( MAX_SS, OUTPUT );
102// //pinMode( BPNT_0, OUTPUT );
103// //pinMode( BPNT_1, OUTPUT );
104// //digitalWrite( BPNT_0, LOW );
105// //digitalWrite( BPNT_1, LOW );
106// Deselect_MAX3421E;
107// pinMode( MAX_RESET, OUTPUT );
108// digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset
109//}
110//byte MAX3421E::getVbusState( void )
111//{
112// return( vbusState );
113//}
114//void MAX3421E::toggle( byte pin )
115//{
116// digitalWrite( pin, HIGH );
117// digitalWrite( pin, LOW );
118//}
119/* Single host register write */
120void MAX3421E::regWr( byte reg, byte val)
121{
122 digitalWrite(MAX_SS,LOW);
123 SPDR = ( reg | 0x02 );
124 while(!( SPSR & ( 1 << SPIF )));
125 SPDR = val;
126 while(!( SPSR & ( 1 << SPIF )));
127 digitalWrite(MAX_SS,HIGH);
128 return;
129}
130/* multiple-byte write */
131/* returns a pointer to a memory position after last written */
132char * MAX3421E::bytesWr( byte reg, byte nbytes, char * data )
133{
134 digitalWrite(MAX_SS,LOW);
135 SPDR = ( reg | 0x02 );
136 while( nbytes-- ) {
137 while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent
138 SPDR = ( *data ); // send next data byte
139 data++; // advance data pointer
140 }
141 while(!( SPSR & ( 1 << SPIF )));
142 digitalWrite(MAX_SS,HIGH);
143 return( data );
144}
145/* GPIO write. GPIO byte is split between 2 registers, so two writes are needed to write one byte */
146/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
147/* upper 4 bits of IOPINS1, IOPINS2 are read-only, so no masking is necessary */
148void MAX3421E::gpioWr( byte val )
149{
150 regWr( rIOPINS1, val );
151 val = val >>4;
152 regWr( rIOPINS2, val );
153
154 return;
155}
156/* Single host register read */
157byte MAX3421E::regRd( byte reg )
158{
159 byte tmp;
160 digitalWrite(MAX_SS,LOW);
161 SPDR = reg;
162 while(!( SPSR & ( 1 << SPIF )));
163 SPDR = 0; //send empty byte
164 while(!( SPSR & ( 1 << SPIF )));
165 digitalWrite(MAX_SS,HIGH);
166 return( SPDR );
167}
168/* multiple-bytes register read */
169/* returns a pointer to a memory position after last read */
170char * MAX3421E::bytesRd ( byte reg, byte nbytes, char * data )
171{
172 digitalWrite(MAX_SS,LOW);
173 SPDR = reg;
174 while(!( SPSR & ( 1 << SPIF ))); //wait
175 while( nbytes ) {
176 SPDR = 0; //send empty byte
177 nbytes--;
178 while(!( SPSR & ( 1 << SPIF )));
179 *data = SPDR;
180 data++;
181 }
182 digitalWrite(MAX_SS,HIGH);
183 return( data );
184}
185/* GPIO read. See gpioWr for explanation */
186/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
187byte MAX3421E::gpioRd( void )
188{
189 byte tmpbyte = 0;
190 tmpbyte = regRd( rIOPINS2 ); //pins 4-7
191 tmpbyte &= 0xf0; //clean lower nibble
192 tmpbyte |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. Upper nibble zeroes during shift, at least with this compiler
193 return( tmpbyte );
194}
195/* reset MAX3421E using chip reset bit. SPI configuration is not affected */
196boolean MAX3421E::reset()
197{
198 byte tmp = 0;
199 regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
200 regWr( rUSBCTL, 0x00 ); //Remove the reset
201 while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL is stable
202 tmp++; //timeout after 256 attempts
203 if( tmp == 0 ) {
204 return( false );
205 }
206 }
207 return( true );
208}
209/* turn USB power on/off */
210/* does nothing, returns TRUE. Left for compatibility with old sketches */
211/* will be deleted eventually */
212///* ON pin of VBUS switch (MAX4793 or similar) is connected to GPOUT7 */
213///* OVERLOAD pin of Vbus switch is connected to GPIN7 */
214///* OVERLOAD state low. NO OVERLOAD or VBUS OFF state high. */
215boolean MAX3421E::vbusPwr ( boolean action )
216{
217// byte tmp;
218// tmp = regRd( rIOPINS2 ); //copy of IOPINS2
219// if( action ) { //turn on by setting GPOUT7
220// tmp |= bmGPOUT7;
221// }
222// else { //turn off by clearing GPOUT7
223// tmp &= ~bmGPOUT7;
224// }
225// regWr( rIOPINS2, tmp ); //send GPOUT7
226// if( action ) {
227// delay( 60 );
228// }
229// if (( regRd( rIOPINS2 ) & bmGPIN7 ) == 0 ) { // check if overload is present. MAX4793 /FLAG ( pin 4 ) goes low if overload
230// return( false );
231// }
232 return( true ); // power on/off successful
233}
234/* probe bus to determine device presense and speed and switch host to this speed */
235void MAX3421E::busprobe( void )
236{
237 byte bus_sample;
238 bus_sample = regRd( rHRSL ); //Get J,K status
239 bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte
240 switch( bus_sample ) { //start full-speed or low-speed host
241 case( bmJSTATUS ):
242 if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
243 regWr( rMODE, MODE_FS_HOST ); //start full-speed host
244 vbusState = FSHOST;
245 }
246 else {
247 regWr( rMODE, MODE_LS_HOST); //start low-speed host
248 vbusState = LSHOST;
249 }
250 break;
251 case( bmKSTATUS ):
252 if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
253 regWr( rMODE, MODE_LS_HOST ); //start low-speed host
254 vbusState = LSHOST;
255 }
256 else {
257 regWr( rMODE, MODE_FS_HOST ); //start full-speed host
258 vbusState = FSHOST;
259 }
260 break;
261 case( bmSE1 ): //illegal state
262 vbusState = SE1;
263 break;
264 case( bmSE0 ): //disconnected state
Erik Gillingf3572d72011-02-17 20:40:57 -0800265 regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ);
Erik Gilling51f17512011-02-17 20:39:36 -0800266 vbusState = SE0;
267 break;
268 }//end switch( bus_sample )
269}
270/* MAX3421E initialization after power-on */
271void MAX3421E::powerOn()
272{
273 /* Configure full-duplex SPI, interrupt pulse */
274 regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL + bmGPXB )); //Full-duplex SPI, level interrupt, GPX
275 if( reset() == false ) { //stop/start the oscillator
276 Serial.println("Error: OSCOKIRQ failed to assert");
277 }
278
279 /* configure host operation */
280 regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ ); // set pull-downs, Host, Separate GPIN IRQ on GPX
281 regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection
282 /* check if device is connected */
283 regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus
284 while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish
285 busprobe(); //check if anything is connected
286 regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt
287 regWr( rCPUCTL, 0x01 ); //enable interrupt pin
288}
289/* MAX3421 state change task and interrupt handler */
290byte MAX3421E::Task( void )
291{
292 byte rcode = 0;
293 byte pinvalue;
294 //Serial.print("Vbus state: ");
295 //Serial.println( vbusState, HEX );
Erik Gillingbb9ab4b2011-02-17 20:41:12 -0800296 pinvalue = readINT();
297 if( pinvalue == LOW ) {
Erik Gilling51f17512011-02-17 20:39:36 -0800298 rcode = IntHandler();
299 }
Erik Gillingbb9ab4b2011-02-17 20:41:12 -0800300 pinvalue = readGPX();
Erik Gilling51f17512011-02-17 20:39:36 -0800301 if( pinvalue == LOW ) {
302 GpxHandler();
303 }
304// usbSM(); //USB state machine
305 return( rcode );
306}
307byte MAX3421E::IntHandler()
308{
309 byte HIRQ;
310 byte HIRQ_sendback = 0x00;
311 HIRQ = regRd( rHIRQ ); //determine interrupt source
312 //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
313 // HIRQ_sendback |= bmFRAMEIRQ;
314 //}//end FRAMEIRQ handling
315 if( HIRQ & bmCONDETIRQ ) {
316 busprobe();
317 HIRQ_sendback |= bmCONDETIRQ;
318 }
319 /* End HIRQ interrupts handling, clear serviced IRQs */
320 regWr( rHIRQ, HIRQ_sendback );
321 return( HIRQ_sendback );
322}
323byte MAX3421E::GpxHandler()
324{
325 byte GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
326// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload
327// vbusPwr( OFF ); //attempt powercycle
328// delay( 1000 );
329// vbusPwr( ON );
330// regWr( rGPINIRQ, bmGPINIRQ7 );
331// }
332 return( GPINIRQ );
333}
334
335//void MAX3421E::usbSM( void ) //USB state machine
336//{
337//
338//
Erik Gillingbb9ab4b2011-02-17 20:41:12 -0800339//}