/*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include //#include //#include //#include //#include #include #include #include #include #include #include "clock.h" //#include //#include #ifdef DEBUGVLYNQ #define DEBUG_VLYNQ(args...) printk(KERN_INFO"###VLYNQ###: " args) #else #define DEBUG_VLYNQ(args...) /* args */ #endif static int wlan_reset_device( void ); static int wlan_unreset_device( void ); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _vlynq_context *vlynq_config=NULL; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int vlynq_startup_link(volatile struct _vlynq_registers *V, unsigned int vlynq_clock, unsigned int reset_bit) { unsigned int count, clk=243000000/3, divisor; printk("[vlynq_startup_link] \n"); /*----------------------------------------------------------------------------------*\ * device aus den reset holen \*----------------------------------------------------------------------------------*/ //if(reset_bit != (unsigned int)-1) // wlan_unreset_device(); //ohio_reset_device(reset_bit, 10); V->local.Control.Bits.reset = 1; ndelay(100); V->local.Control.Register = 0; #if 0 /* Sascha: Ist immer PLL1/6 (Arm Takt ist PLL1/2) */ /*----------------------------------------------------------------------------------*\ * clock divider einstellen \*----------------------------------------------------------------------------------*/ clk = get_clock(avm_clock_id_system); #else divisor = clk / vlynq_clock; DEBUG_VLYNQ("vlynq_clock=%d clk=%d divisor=%d", vlynq_clock, clk, divisor); if(clk / divisor != vlynq_clock) { printk(KERN_WARNING "Warning: configurated vlynq clock not reached (config %uHz) set %uHz\n", vlynq_clock, clk / divisor); } V->local.Control.Bits.clkdir = 1; /* 1 clk from divisor */ V->local.Control.Bits.clkdiv = 1; //divisor-1; /* clkdiv + 1 = divisor*/ #endif /*----------------------------------------------------------------------------------*\ * pruefen ob der Link vorhanden ist \*----------------------------------------------------------------------------------*/ for(count = 0 ; count < 10 ; count++) { udelay(64); /*--- 64 uSekunden warten ----*/ if(V->local.Status.Bits.link) break; } if(V->local.Status.Bits.link == 0) { V->local.Control.Bits.reset = 1; wlan_reset_device(); printk(KERN_ERR "Error: vlynq link could not be established\n"); return 1; }else{ DEBUG_VLYNQ("Link established!\n"); } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int wlan_reset_device( void ) { /* WLAN muss ueber i2c extender aus dem Reset geholt werden */ davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, WLAN_RESET, 0); return 1; } static int wlan_unreset_device( void ) { /* Turn Debug_LED on*/ //davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, DEBUG_LED, 0); //davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, DEBUG_LED, 1); davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, WLAN_RESET, 1); return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int vlynq_release_link( void ) { /*Schicke VlynqController in den Reset*/ wlan_reset_device(); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int vlynq_init(void) { unsigned int reset_bit; unsigned int int_nr, ret; /*--- unsigned char *mac = "\x00\x04\x0e\x12\x34\x56"; ---*/ #if 1 /*--- zum testen des WLAN-Modul aus dem reset holen ---*/ DEBUG_VLYNQ("Unreset Vlynq!\n"); wlan_unreset_device(); DEBUG_VLYNQ("Allocate Context!\n"); vlynq_config=vlynq_alloc_context(); #endif DEBUG_VLYNQ("INITIALIZING...\n"); /* Wurde Speicher fuer die Instance angelegt? */ if ( vlynq_config == NULL ) return 1; /* Wurde die Vlynqinstanze bereits initialisiert? */ if( vlynq_config->vlynq==NULL) { vlynq_config->vlynq = (volatile struct _vlynq_registers *)io_p2v(DAVINCI_VLYNQ_BASE); reset_bit = -1; int_nr = IRQ_VLQINT; /* Set PINMUX0 Register: VLYNQEN = 1 and VLYNQWD = 0x3 */ __REG(DAVINCI_SYSTEM_MODULE_BASE)|=((1<<15)|(0x3<<12)); /*Set BUS-Multiplexer to VLYNQ*/ davinci_i2c_expander_op(CONFIG_DAVINCI_I2C_EXPANDER_ADDR, VLYNQ_ON, 0); /* Enable VLYNQ Module */ board_set_module_state_psc(DAVINCI_LPSC_VLYNQ, PSC_Enable); if(vlynq_startup_link(vlynq_config->vlynq, CONFIG_VLYNQ_SUPPORT_CLK, reset_bit)) { return 2; } /*--- register vlynq interrupt ---*/ ret = request_irq(int_nr, vlynq_interrupt, SA_INTERRUPT, "VLYNQ", vlynq_config); if (ret) { printk(KERN_INFO "[ohio_vlynq_init] request_irq %d failed, reason %d\n", int_nr, ret); return ret; } } return 0; /* success */ } #if 0 /*--- zum testen ---*/ late_initcall(vlynq_init); #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int vlynq_config_memory_windows(volatile struct _vlynq_registers_half *VL, volatile struct _vlynq_registers_half *VR, struct ___vlynq_Rx_Address LocalWindows[], unsigned int LocalWindowCount, unsigned int RemoteTxAddr) { unsigned int i; if(LocalWindowCount > 4) { printk(KERN_ERR "ERROR: vlynq: maximal 4 windows allowed\n"); return 1; } VR->Tx_Address = RemoteTxAddr; DEBUG_VLYNQ("Tx_Address=0x%.8x\n", RemoteTxAddr); for(i = 0 ; i < LocalWindowCount ; i++) { VL->Rx_Address[i] = LocalWindows[i]; DEBUG_VLYNQ("Rx_Address=0x%.8x\n", LocalWindows[i].Offset); DEBUG_VLYNQ("Rx_Size=0x%.8x\n\n", LocalWindows[i].Size); } for( ; i < 4 ; i++) { VL->Rx_Address[i].Size = 0; VL->Rx_Address[i].Offset = 0; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int vlynq_config_interrupt(volatile struct _vlynq_registers_half *V, volatile struct _vlynq_interrupts *Irq) { unsigned int val; if(Irq->LocalEnable == VLYNQ_INT_OFF) { return 0; } /* Map local module status interrupts to interrupt vector*/ val = ((Irq->vector) & 0x1F) << VLYNQ_CTL_INTVEC_SHIFT ; /*--- set vector to virtual interrupt ---*/ Irq->irq = 0; //TEMP - vlynq_vector_to_irq(Irq->vector); /* enable local module status interrupts */ val |= 1 << VLYNQ_CTL_INTEN_SHIFT; /*--- enable später ---*/ if (Irq->LocalEnable == VLYNQ_INT_LOCAL ) { /*set the intLocal bit*/ val |= 1 << VLYNQ_CTL_INTLOCAL_SHIFT; } /* Irrespective of whether interrupts are handled locally, program * int2Cfg. Error checking for accidental loop(when intLocal=0 and int2Cfg=1 * i.e remote packets are set intPending register->which will result in * same packet being sent out) has been done already */ if (Irq->RemoteEnable == VLYNQ_INT_ROOT_ISR) { /* Set the int2Cfg register, so that remote interrupt * packets are written to intPending register */ val |= 1 << VLYNQ_CTL_INT2CFG_SHIFT; /* Set intPtr register to point to intPending register */ V->Interrupt_Pointer = ((unsigned int)&(V->Interrupt_Pending_Set) & 0xFF); } else { /*set the interrupt pointer register*/ /*--- VL->Interrupt_Pointer = local interrupt pointer adresse ---*/ /*--- V->Interrupt_Pointer = TODO ---*/ panic("set interrupt pointer register to Interruptcontroller not implemented\n"); val &= ~(1 << VLYNQ_CTL_INT2CFG_SHIFT); } DEBUG_VLYNQ("ControlReg (0x%08x) = 0x%08X\n",(unsigned int)(&V->Control.Register), V->Control.Register); V->Control.Register = (V->Control.Register & ~((1 << VLYNQ_CTL_INT2CFG_SHIFT) || (1 << VLYNQ_CTL_INTLOCAL_SHIFT) || (1 << VLYNQ_CTL_INTEN_SHIFT))) | val; DEBUG_VLYNQ("Set Interr.-Ctrl = 0x%08x\n",val); DEBUG_VLYNQ("ControlReg (0x%08x) = 0x%08x\n",&V->Control, V->Control.Register); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int vlynq_init_link( void ) { unsigned int ret; volatile struct _vlynq_registers *V = NULL; struct _vlynq_context* context=NULL; context=vlynq_config; if(context==NULL) return 1; V = context->vlynq; DEBUG_VLYNQ("Remote => Local\n"); ret = vlynq_config_memory_windows(&(V->local), &(V->remote), context->Remote2Local.Windows, context->Remote2Local.WindowCount, context->Remote2Local.Tx_Address); if(ret) return ret; DEBUG_VLYNQ("Local => Remote\n"); ret = vlynq_config_memory_windows(&(V->remote), &(V->local), context->Local2Remote.Windows, context->Local2Remote.WindowCount, context->Local2Remote.Tx_Address); if(ret) return ret; /*--------------------------------------------------------------------------------------*\ * ggf. noch diverse Parameter setzen \*--------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------*\ * Configure Interrupt Priority Vector Status/Clear Register \*--------------------------------------------------------------------------------------*/ #warning "Sascha: Sollte in eine eigene Funktion ausgelagert\n" V->local.Interrupt_Priority.Bits.intstat=0x7; V->local.Interrupt_Priority.Bits.nointpend=0; /*--------------------------------------------------------------------------------------*\ * Interrupt aktivieren \*--------------------------------------------------------------------------------------*/ DEBUG_VLYNQ("LOCAL INTERRUPT aktivieren\n"); ret = vlynq_config_interrupt(&(V->local), &(context->LocalIrq)); if(ret) { return ret; } DEBUG_VLYNQ("REMOTE INTERRUPT aktivieren\n"); ret = vlynq_config_interrupt(&(V->remote), &(context->RemoteIrq)); if(ret) { return ret; } /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ DEBUG_VLYNQ("Startup Vlynq Link\n"); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _vlynq_context *vlynq_alloc_context( void ) { struct _vlynq_context *C; C = kmalloc(sizeof(struct _vlynq_context), GFP_ATOMIC); if(C) { memset(C, 0, sizeof(*C)); C->instance = 0; vlynq_config=C; } return C; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int vlynq_free_context( void ) { free_irq(IRQ_VLQINT, vlynq_config); vlynq_release_link(); kfree(vlynq_config); vlynq_config=NULL; return 0; } /*------------------------------------------------------------------------------------------*\ V->local.Control.Bits.reset = 0; V->local.Control.Bits.iloop = 0; V->local.Control.Bits.aopt_disable = 0; V->local.Control.Bits.int2cfg = 1: V->local.Control.Bits.intvec = 0; / * 5-Bit Vector * / V->local.Control.Bits.intenable = 0; / * 1 enable, 0 disable * / V->local.Control.Bits.intlocal = 1; / * 1 local, 0 remote * / V->local.Control.Bits.clkdir = 1; / * 1 clk from divisor * / V->local.Control.Bits.clkdiv = divisor; V->local.Control.Bits.txfastpath = 0; / * buffered or not * / V->local.Control.Bits.rtmenable = 0; V->local.Control.Bits.rtmvalidwr = 0; V->local.Control.Bits.rxsampleval = 0; V->local.Control.Bits.sclkpudis = V->local.Control.Bits.pmen = \*------------------------------------------------------------------------------------------*/ /* =============== EXPORT SYMBOLS ============= */ EXPORT_SYMBOL(vlynq_init); EXPORT_SYMBOL(vlynq_init_link); EXPORT_SYMBOL(vlynq_free_context ); EXPORT_SYMBOL(vlynq_alloc_context); #if 0 EXPORT_SYMBOL(vlynq_get_irq); EXPORT_SYMBOL(vlynq_irq_vector_setup); EXPORT_SYMBOL(vlynq_vector_to_irq); EXPORT_SYMBOL(vlynq_interrupt); EXPORT_SYMBOL(vlynq_irq_status); EXPORT_SYMBOL(vlynq_irq_enable_mask); EXPORT_SYMBOL(vlynq_irq_enable); EXPORT_SYMBOL(vlynq_irq_disable); EXPORT_SYMBOL(vlynq_irq_ack); #endif