1 /*
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 
30 /* MAX3421E USB host controller support */
31 
32 #include "Max3421e.h"
33 // #include "Max3421e_constants.h"
34 
35 static byte vbusState;
36 
37 /* Functions    */
38 
39 #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 
setRST(uint8_t val)55 void MAX3421E::setRST(uint8_t val)
56 {
57 	if (val == LOW)
58 		RST_PORT &= ~_BV(RST);
59 	else
60 		RST_PORT |= _BV(RST);
61 }
62 
readINT(void)63 uint8_t MAX3421E::readINT(void)
64 {
65 	return INT_PIN & _BV(INT) ? HIGH : LOW;
66 }
67 
readGPX(void)68 uint8_t MAX3421E::readGPX(void)
69 {
70 	// return GPX_PIN & _BV(GPX) ? HIGH : LOW;
71 	return LOW;
72 }
73 
74 
pinInit(void)75 void 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 
84 /* Constructor */
MAX3421E()85 MAX3421E::MAX3421E()
86 {
87     spi_init();
88 	pinInit();
89 }
90 
getVbusState(void)91 byte 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   */
regWr(byte reg,byte val)120 void 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 */
bytesWr(byte reg,byte nbytes,char * data)132 char * 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 */
gpioWr(byte val)148 void 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        */
regRd(byte reg)157 byte 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   */
bytesRd(byte reg,byte nbytes,char * data)170 char * 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    */
gpioRd(void)187 byte 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   */
reset()196 boolean 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.              */
vbusPwr(boolean action)215 boolean 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 */
busprobe(void)235 void 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
265 		regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ);
266             vbusState = SE0;
267             break;
268         }//end switch( bus_sample )
269 }
270 /* MAX3421E initialization after power-on   */
powerOn()271 void 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 */
Task(void)290 byte MAX3421E::Task( void )
291 {
292  byte rcode = 0;
293  byte pinvalue;
294     //Serial.print("Vbus state: ");
295     //Serial.println( vbusState, HEX );
296  pinvalue = readINT();
297  if( pinvalue  == LOW ) {
298         rcode = IntHandler();
299     }
300     pinvalue = readGPX();
301     if( pinvalue == LOW ) {
302         GpxHandler();
303     }
304 //    usbSM();                                //USB state machine
305     return( rcode );
306 }
IntHandler()307 byte 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 }
GpxHandler()323 byte 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 //
339 //}
340