/* * Copyright (c) 2010 -2013 Espressif System. * * sdio serial i/f driver * - sdio device control routines * - sync/async DMA/PIO read/write * */ #ifdef ESP_USE_SPI #include #include #include #include #include #include #include #include "esp_pub.h" #include "esp_sif.h" #include "esp_sip.h" #include "esp_debug.h" #include "slc_host_register.h" #include "esp_version.h" #include "esp_ctrl.h" #ifdef ANDROID #include "esp_android.h" #endif /* ANDROID */ #ifdef USE_EXT_GPIO #include "esp_ext.h" #endif /* USE_EXT_GPIO */ static int __init esp_spi_init(void); static void __exit esp_spi_exit(void); #define SPI_BLOCK_SIZE (512) #define MAX_BUF_SIZE (48*1024) static unsigned char *buf_addr = NULL; static unsigned char *tx_cmd; static unsigned char *rx_cmd; struct task_struct *sif_irq_thread; #define ESP_DMA_IBUFSZ 2048 //unsigned int esp_msg_level = 0; unsigned int esp_msg_level = ESP_DBG_ERROR | ESP_SHOW; static struct semaphore esp_powerup_sem; static enum esp_sdio_state sif_sdio_state; struct esp_spi_ctrl *sif_sctrl = NULL; #ifdef ESP_ANDROID_LOGGER bool log_off = false; #endif /* ESP_ANDROID_LOGGER */ struct sif_req * sif_alloc_req(struct esp_spi_ctrl *sctrl); #include "spi_stub.c" void sif_lock_bus(struct esp_pub *epub) { EPUB_FUNC_CHECK(epub); spi_bus_lock(EPUB_TO_FUNC(epub)->master); } void sif_unlock_bus(struct esp_pub *epub) { EPUB_FUNC_CHECK(epub); spi_bus_unlock(EPUB_TO_FUNC(epub)->master); } int sif_spi_write_then_read(struct spi_device *spi, unsigned char* bufwrite, int sizesend, unsigned char* bufread, int sizeread) { int error; error = spi_write_then_read(spi, bufwrite,sizesend, bufread, sizeread); if (error) { esp_dbg(ESP_DBG_ERROR, "%s: failed, error: %d\n", __func__, error); return error; } return 0; } int sif_spi_write_async_read(struct spi_device *spi, unsigned char* bufwrite,unsigned char* bufread,int size) { struct spi_transfer xfer = { .rx_buf = bufread, .tx_buf = bufwrite, .len = size, .bits_per_word = 8, .speed_hz = SPI_FREQ, }; struct spi_message msg; int error; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); error = spi_sync_locked(spi, &msg); if (error) { esp_dbg(ESP_DBG_ERROR, "%s: failed, error: %d\n", __func__, error); return error; } return 0; } int sif_spi_write_raw(struct spi_device *spi, unsigned char* buf, int size) { int err; struct spi_transfer xfer = { .tx_buf = buf, .len = size, .bits_per_word = 8, .speed_hz = SPI_FREQ, }; struct spi_message msg; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); err = spi_sync_locked(spi, &msg); if (err) { esp_dbg(ESP_DBG_ERROR, "%s: failed, error: %d\n", __func__, err); return err; } return 0; } int sif_spi_read_raw(struct spi_device *spi, unsigned char* buf, int size) { memset(buf,0xff,size); return sif_spi_write_async_read(spi,buf,buf,size); } int sif_spi_write_bytes(struct spi_device *spi, unsigned int addr, unsigned char *src,int count, int check_idle) { int i; int pos,len; unsigned char *tx_data = (unsigned char*)src; int err_ret = 0; u32 timeout = 25000; u32 busy_state = 0x00; ASSERT(spi != NULL); if (check_idle) { timeout = 25000; do { busy_state = 0x00; sif_spi_read_raw(spi, (u8 *)&busy_state, 4); if(busy_state != 0xffffffff) esp_dbg(ESP_DBG_ERROR, "%s busy_state:%x\n", __func__, busy_state); } while (busy_state != 0xffffffff && --timeout > 0); } if (timeout < 24000) esp_dbg(ESP_DBG_ERROR, "%s timeout[%d]\n", __func__, timeout); if(count > 512 ) { err_ret = -1; goto goto_err; } tx_cmd[0]=0x75; if( addr >= (1<<17) ) { err_ret = -2; goto goto_err; } else { tx_cmd[1]=0x90|0x04|(addr>>15); //0x94; tx_cmd[2]=addr>>7; if(count == 512 ) { tx_cmd[3]=( addr<<1|0x0 ); tx_cmd[4]= 0x00; //0x08; } else { tx_cmd[3]=( addr<<1|count>>7 ); tx_cmd[4]= count; //0x08; } } tx_cmd[5]=0x01; pos = 5+1; //Add cmd respon memset(tx_cmd+pos,0xff,CMD_RESP_SIZE); pos =pos+ CMD_RESP_SIZE; //Add token tx_cmd[pos]=0xFE; pos = pos+1; //Add data memcpy(tx_cmd+pos,tx_data,count); pos = pos+count; //Add data respon memset(tx_cmd+pos,0xff,DATA_RESP_SIZE_W); pos = pos+ DATA_RESP_SIZE_W; if( pos%8 ) { len = (8 - pos%8); memset(tx_cmd+pos,0xff,len); } else len = 0; sif_spi_write_async_read(spi, tx_cmd,tx_cmd,pos+len); pos = 5+1; for(i=0;i=CMD_RESP_SIZE) { esp_dbg(ESP_DBG_ERROR, "write data resp 0x00 no recv\n"); err_ret = -3; goto goto_err; } pos = pos+CMD_RESP_SIZE+count+1; for(i=0;i=DATA_RESP_SIZE_W) { esp_dbg(ESP_DBG_ERROR, "write data resp 0xE5 no recv\n"); err_ret = -3; goto goto_err; } goto_err: return err_ret; } int sif_spi_write_blocks(struct spi_device *spi, unsigned int addr,unsigned char *src, int count, int check_idle) { int err_ret = 0; int i,j; int n; int pos,len; unsigned char *tx_data = (unsigned char*)src; u32 busy_state = 0x00; u32 timeout = 25000; //esp_dbg(ESP_DBG_ERROR, "Block Write ---------"); ASSERT(spi != NULL); #if 1 if (check_idle) { timeout = 25000; do { busy_state = 0x00; sif_spi_read_raw(spi, (u8 *)&busy_state, 4); if(busy_state != 0xffffffff) esp_dbg(ESP_DBG_ERROR, "%s busy_state:%x\n", __func__, busy_state); } while (busy_state != 0xffffffff && --timeout > 0); } if (timeout < 24000) esp_dbg(ESP_DBG_ERROR, "%s timeout[%d]\n", __func__, timeout); #endif //esp_dbg(ESP_DBG_ERROR, "Block Write ---------"); tx_cmd[0]=0x75; if( count <=0 ) { err_ret = -1; goto goto_err; } if( addr >= (1<<17) ) { err_ret = -2; goto goto_err; } else { tx_cmd[1]=0x90|0x0C|(addr>>15); tx_cmd[2]=addr>>7; if(count >= 512 ) { tx_cmd[3]=( addr<<1|0x0 ); tx_cmd[4]= 0x00; } else { tx_cmd[3]=( addr<<1|count>>7 ); tx_cmd[4]= count; } } tx_cmd[5]=0x01; pos = 5+1; //Add cmd respon memset(tx_cmd+pos,0xff,CMD_RESP_SIZE); pos =pos+ CMD_RESP_SIZE; for(j=0;j=CMD_RESP_SIZE) { esp_dbg(ESP_DBG_ERROR, "1st block write cmd resp 0x00 no recv, %d\n", count); err_ret = -3; goto goto_err; } pos = pos+CMD_RESP_SIZE; for(j=0;j=n) { esp_dbg(ESP_DBG_ERROR, "%s block%d write data rsp error, %d\n", __func__, j+1, count); err_ret = -4; goto goto_err; } pos = pos+n; } #if 0 //Add stop token pos = 0; tx_cmd[pos]=0xFD; pos = pos+1; //Add data respon memset(tx_cmd+pos , 0xff , BLOCK_W_DATA_RESP_SIZE_FINAL); pos = pos+ BLOCK_W_DATA_RESP_SIZE_FINAL; eagle_spi_write_async_read(tx_cmd,tx_cmd,pos); //Judge Final busy bits. pos = 1; for(i=0;i=BLOCK_W_DATA_RESP_SIZE_FINAL) { mutex_unlock(&RWMutex); esp_dbg(ESP_DBG_ERROR, "blocks final busy bit no recv"); return -5; } #endif goto_err: return err_ret; } int sif_spi_write_mix_nosync(struct spi_device *spi, unsigned int addr, unsigned char *buf, int len, int check_idle) { int blk_cnt; int remain_len; int err; blk_cnt = len/SPI_BLOCK_SIZE; remain_len = len%SPI_BLOCK_SIZE; if (blk_cnt > 0) { err = sif_spi_write_blocks(spi, addr, buf, blk_cnt, check_idle); if (err) return err; } if (remain_len > 0) { err = sif_spi_write_bytes(spi, addr, (buf + (blk_cnt*SPI_BLOCK_SIZE)), remain_len, check_idle); if (err) return err; } return 0; } int sif_spi_write_mix_sync(struct spi_device *spi, unsigned int addr, unsigned char *buf, int len, int check_idle) { int err; spi_bus_lock(spi->master); err = sif_spi_write_mix_nosync(spi, addr, buf, len, check_idle); spi_bus_unlock(spi->master); return err; } int sif_spi_epub_write_mix_nosync(struct esp_pub *epub, unsigned int addr, unsigned char *buf,int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; ASSERT(epub != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); return sif_spi_write_mix_nosync(spi, addr, buf, len, check_idle); } int sif_spi_epub_write_mix_sync(struct esp_pub *epub, unsigned int addr, unsigned char *buf,int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; ASSERT(epub != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); return sif_spi_write_mix_sync(spi, addr, buf, len, check_idle); } int sif_spi_read_bytes(struct spi_device *spi, unsigned int addr,unsigned char *dst, int count, int check_idle) { int pos,total_num,len; int i; unsigned char *rx_data = (unsigned char *)dst; int err_ret = 0; u32 timeout = 25000; u32 busy_state = 0x00; ASSERT(spi != NULL); rx_cmd[0]=0x75; if (check_idle) { timeout = 25000; do { busy_state = 0x00; sif_spi_read_raw(spi, (u8 *)&busy_state, 4); if(busy_state != 0xffffffff) esp_dbg(ESP_DBG_ERROR, "%s busy_state:%x\n", __func__, busy_state); } while (busy_state != 0xffffffff && --timeout > 0); } if (timeout < 24000) esp_dbg(ESP_DBG_ERROR, "%s timeout[%d]\n", __func__, timeout); if(count > 512 ) { err_ret = -1; goto goto_err; } if( addr >= (1<<17) ) { err_ret = -2; goto goto_err; } else { rx_cmd[1]=0x10|0x04|(addr>>15); //0x94; rx_cmd[2]=addr>>7; if(count == 512 ) { rx_cmd[3]=( addr<<1|0x0 ); rx_cmd[4]= 0x00; //0x08; } else { rx_cmd[3]=( addr<<1|count>>7 ); rx_cmd[4]= count; //0x08; } } rx_cmd[5]=0x01; #if 1 // one shot read total_num = CMD_RESP_SIZE+DATA_RESP_SIZE_R+count+2; memset(rx_cmd+6 , 0xFF ,total_num); if( (6+total_num)%8 ) { len = (8 - (6+total_num)%8); memset(rx_cmd+6+total_num,0xff,len); } else len = 0; sif_spi_write_async_read(spi, rx_cmd,rx_cmd,6+total_num+len); pos = 5+1; for(i=0;i=CMD_RESP_SIZE) { esp_dbg(ESP_DBG_ERROR, "read cmd resp 0x00 no recv\n"); /***********error info************************/ /* char t = pos; while ( t < pos+32) { printk(KERN_ERR "rx:[0x%02x] ", rx_cmd[t]); t++; if ((t-pos)%8 == 0) printk(KERN_ERR "\n"); } */ err_ret = -3; goto goto_err; } //esp_dbg(ESP_DBG_ERROR, "0x00 pos:%d",pos+i); pos = pos+i+2; for(i=0;i=DATA_RESP_SIZE_R) { esp_dbg(ESP_DBG_ERROR, "read data resp 0xFE no recv\n"); err_ret = -4; goto goto_err; } //esp_dbg(ESP_DBG_ERROR, "0xFE pos:%d",pos+i); pos = pos+i+1; memcpy(rx_data,rx_cmd+pos,count); #else //wait method memset(rx_cmd+6,0xFF,CMD_RESP_SIZE+DATA_RESP_SIZE_R+count+2); //printk(KERN_ERR "mark 1",pos+i); sif_spi_write_async_read(spi, rx_cmd,rx_cmd,6+CMD_RESP_SIZE+DATA_RESP_SIZE_R+count+2); //printk(KERN_ERR "mark 2",pos+i); pos = 5+1; for(i=0;i=CMD_RESP_SIZE) { printk(KERN_ERR "read cmd resp 0x00 no recv\n"); //kfree(rx_cmd); err_ret = -3; goto goto_err; } //printk(KERN_ERR "0x00 pos:%d",pos+i); pos = pos+i+2; for(i=0;i=DATA_RESP_SIZE_R) { printk(KERN_ERR "read data resp 0xFE no recv\n"); err_ret = -4; goto goto_err; } //printk(KERN_ERR "0xFE pos:%d",pos+i); pos = pos+i+1; for(i=0;i 0); } if (timeout < 24000) esp_dbg(ESP_DBG_ERROR, "%s timeout[%d]\n", __func__, timeout); #endif rx_cmd[0]=0x75; if( count <=0 ) { err_ret = -1; goto goto_err; } if( addr >= (1<<17) ) { err_ret = -2; goto goto_err; } else { rx_cmd[1]=0x10|0x0C|(addr>>15); rx_cmd[2]=addr>>7; if(count >= 512 ) { rx_cmd[3]=( addr<<1|0x0 ); rx_cmd[4]= 0x00; } else { rx_cmd[3]=( addr<<1|count>>7 ); rx_cmd[4]= count; } } rx_cmd[5]=0x01; total_num = CMD_RESP_SIZE+BLOCK_R_DATA_RESP_SIZE_1ST+SPI_BLOCK_SIZE+ 2 + (count-1)*(BLOCK_R_DATA_RESP_SIZE_EACH+SPI_BLOCK_SIZE+2); memset(rx_cmd+6, 0xFF ,total_num); if( (6+total_num)%8 ) { len = (8 - (6+total_num)%8); memset(rx_cmd+6+total_num,0xff,len); } else len = 0; sif_spi_write_async_read(spi, rx_cmd,rx_cmd,6+total_num+len ); pos = 5+1; for(i=0;i=CMD_RESP_SIZE) { esp_dbg(ESP_DBG_ERROR, "block read cmd resp 0x00 no recv\n"); #if 0 char t = pos; while ( t < pos+32) { printk(KERN_ERR "rx:[0x%02x] ", rx_cmd[t]); t++; if ((t-pos)%8 == 0) printk(KERN_ERR "\n"); } #endif err_ret = -3; goto goto_err; } pos = pos+i+2; for(i=0;i=BLOCK_R_DATA_RESP_SIZE_1ST) { esp_dbg(ESP_DBG_ERROR, "1st block read data resp 0xFE no recv\n"); err_ret = -4; goto goto_err; } pos = pos+i+1; memcpy(rx_data,rx_cmd+pos,SPI_BLOCK_SIZE); pos = pos +SPI_BLOCK_SIZE + 2; for(j=1;j=BLOCK_R_DATA_RESP_SIZE_EACH) { esp_dbg(ESP_DBG_ERROR, "block%d read data resp 0xFE no recv,total:%d\n",j+1,count); err_ret = -4; goto goto_err; } pos = pos+i+1; memcpy(rx_data+j*SPI_BLOCK_SIZE,rx_cmd+pos,SPI_BLOCK_SIZE); pos = pos +SPI_BLOCK_SIZE + 2; } goto_err: return err_ret; } int sif_spi_read_mix_nosync(struct spi_device *spi, unsigned int addr, unsigned char *buf, int len, int check_idle) { int blk_cnt; int remain_len; int err; blk_cnt = len/SPI_BLOCK_SIZE; remain_len = len%SPI_BLOCK_SIZE; if (blk_cnt > 0) { err = sif_spi_read_blocks(spi, addr, buf, blk_cnt, check_idle); if (err) return err; } if (remain_len > 0) { err = sif_spi_read_bytes(spi, addr, (buf + (blk_cnt*SPI_BLOCK_SIZE)), remain_len, check_idle); if (err) return err; } return 0; } int sif_spi_read_mix_sync(struct spi_device *spi, unsigned int addr, unsigned char *buf, int len, int check_idle) { int err; spi_bus_lock(spi->master); err = sif_spi_read_mix_nosync(spi, addr, buf, len, check_idle); spi_bus_unlock(spi->master); return err; } int sif_spi_epub_read_mix_nosync(struct esp_pub *epub, unsigned int addr, unsigned char *buf,int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; ASSERT(epub != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); return sif_spi_read_mix_nosync(spi, addr, buf, len, check_idle); } int sif_spi_epub_read_mix_sync(struct esp_pub *epub, unsigned int addr, unsigned char *buf,int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; ASSERT(epub != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); return sif_spi_read_mix_sync(spi, addr, buf, len, check_idle); } int sif_spi_read_sync(struct esp_pub *epub, unsigned char *buf, int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; u32 read_len; ASSERT(epub != NULL); ASSERT(buf != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); switch(sctrl->target_id) { case 0x100: read_len = len; break; case 0x600: read_len = roundup(len, sctrl->slc_blk_sz); break; default: read_len = len; break; } return sif_spi_read_mix_sync(spi, sctrl->slc_window_end_addr - 2 - (len), buf, read_len, check_idle); } int sif_spi_write_sync(struct esp_pub *epub, unsigned char *buf, int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; u32 write_len; ASSERT(epub != NULL); ASSERT(buf != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); switch(sctrl->target_id) { case 0x100: write_len = len; break; case 0x600: write_len = roundup(len, sctrl->slc_blk_sz); break; default: write_len = len; break; } return sif_spi_write_mix_sync(spi, sctrl->slc_window_end_addr - (len), buf, write_len, check_idle); } int sif_spi_read_nosync(struct esp_pub *epub, unsigned char *buf, int len, int check_idle, bool noround) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; u32 read_len; ASSERT(epub != NULL); ASSERT(buf != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); switch(sctrl->target_id) { case 0x100: read_len = len; break; case 0x600: if (!noround) read_len = roundup(len, sctrl->slc_blk_sz); else read_len = len; break; default: read_len = len; break; } return sif_spi_read_mix_nosync(spi, sctrl->slc_window_end_addr - 2 - (len), buf, read_len, check_idle); } int sif_spi_write_nosync(struct esp_pub *epub, unsigned char *buf, int len, int check_idle) { struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; u32 write_len; ASSERT(epub != NULL); ASSERT(buf != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); switch(sctrl->target_id) { case 0x100: write_len = len; break; case 0x600: write_len = roundup(len, sctrl->slc_blk_sz); break; default: write_len = len; break; } return sif_spi_write_mix_nosync(spi, sctrl->slc_window_end_addr - (len), buf, write_len, check_idle); } void sif_spi_protocol_init(struct spi_device *spi) { unsigned char spi_proto_ini_status = 0; unsigned char rx_buf1[10]; unsigned char tx_buf1[10]; unsigned char dummy_tx_buf[10]; memset(dummy_tx_buf,0xff,sizeof(dummy_tx_buf)); do { if( spi_proto_ini_status == 0 ) { do { tx_buf1[0]=0x40; tx_buf1[1]=0x00; tx_buf1[2]=0x00; tx_buf1[3]=0x00; tx_buf1[4]=0x00; tx_buf1[5]=0x95; //printf("CMD0 \n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); mdelay(100); }while( rx_buf1[2] != 0x01 ); // }while(1); } else if( spi_proto_ini_status == 1 ) { tx_buf1[0]=0x45; tx_buf1[1]=0x00; tx_buf1[2]=0x20; //0x04; tx_buf1[3]=0x00; tx_buf1[4]=0x00; tx_buf1[5]=0x01; //spi_err("CMD 5 1st\n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if( spi_proto_ini_status == 2 ) { tx_buf1[0]=0x45; tx_buf1[1]=0x00; tx_buf1[2]=0x20; tx_buf1[3]=0x00; tx_buf1[4]=0x00; tx_buf1[5]=0x01; //spi_err("CMD5 2nd\n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if( spi_proto_ini_status == 3 ) //CMD 52 addr 0x2, data 0x02; { tx_buf1[0]=0x74; tx_buf1[1]=0x80; tx_buf1[2]=0x00; tx_buf1[3]=0x04; tx_buf1[4]=0x02; tx_buf1[5]=0x01; //spi_err("CMD52 Write addr 02 \n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if( spi_proto_ini_status == 4 ) { tx_buf1[0]=0x74; tx_buf1[1]=0x80; tx_buf1[2]=0x00; tx_buf1[3]=0x08; tx_buf1[4]=0x03; tx_buf1[5]=0x01; //spi_err("CMD52 Write addr 04 \n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if( spi_proto_ini_status == 5 ) { tx_buf1[0]=0x74; tx_buf1[1]=0x00; tx_buf1[2]=0x00; tx_buf1[3]=0x04; tx_buf1[4]=0x00; tx_buf1[5]=0x01; //spi_err("CMD52 Read addr 0x2 \n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if( spi_proto_ini_status == 6 ) { tx_buf1[0]=0x74; tx_buf1[1]=0x00; tx_buf1[2]=0x00; tx_buf1[3]=0x08; tx_buf1[4]=0x00; tx_buf1[5]=0x01; //spi_err("CMD52 Read addr 0x4 \n"); sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if (spi_proto_ini_status>6 && spi_proto_ini_status<15) { tx_buf1[0]=0x74; tx_buf1[1]=0x10; tx_buf1[2]=0x00; tx_buf1[3]=0xF0+2*(spi_proto_ini_status-7); tx_buf1[4]=0x00; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if (spi_proto_ini_status==15) { //spi_err("CMD52 Write Reg addr 0x110 \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x80; //func0 should be tx_buf1[2]=0x02; tx_buf1[3]=0x20; tx_buf1[4]=(unsigned char)(SPI_BLOCK_SIZE & 0xff); //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); //spi_err("CMD52 Write Reg addr 0x111 \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x80; tx_buf1[2]=0x02; tx_buf1[3]=0x22; tx_buf1[4]=(unsigned char)(SPI_BLOCK_SIZE>>8); //0x00; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); //spi_err("CMD52 Write Reg addr 0x111 \n"); /* set boot mode */ tx_buf1[0]=0x74; tx_buf1[1]=0x80; tx_buf1[2]=0x41; tx_buf1[3]=0xe0; tx_buf1[4]=0x01; //0x00; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); } else if (spi_proto_ini_status==16) { #if 0 //printf("CMD52 Write Reg addr 0x40 \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x80; tx_buf1[4]=0x91; //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); //sif_spi_read_bytes( 0x0c,rx_buf1, 4); //printf("CMD52 Write Reg addr 0x3c \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x78; tx_buf1[4]=0x3f; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); //printf("CMD52 Write Reg addr 0x3d \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x7a; tx_buf1[4]=0x34; //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); // printf("CMD52 Write Reg addr 0x3e \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x7c; tx_buf1[4]=0xfe; //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); //printf("CMD52 Write Reg addr 0x3f \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x7e; tx_buf1[4]=0x00; //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); //printf("CMD52 Write Reg addr 0x40 \n"); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x80; tx_buf1[4]=0xd1; //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); tx_buf1[0]=0x74; tx_buf1[1]=0x90; tx_buf1[2]=0x00; tx_buf1[3]=0x52; tx_buf1[4]=0x30; //0x02; tx_buf1[5]=0x01; sif_spi_write_raw(spi, tx_buf1, 6); sif_spi_write_async_read(spi,dummy_tx_buf, rx_buf1,10); esp_dbg(ESP_DBG_ERROR, "rx:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_buf1[0],rx_buf1[1] ,rx_buf1[2],rx_buf1[3],rx_buf1[4],rx_buf1[5],rx_buf1[6],rx_buf1[7],rx_buf1[8],rx_buf1[9]); #endif } else { break; } // mdelay(500); spi_proto_ini_status++; } while (1); } int sif_spi_read_reg(struct spi_device *spi, unsigned int addr, unsigned char *value ) { unsigned char tx_cmd[6]; unsigned char rx_cmd[20]; int err_ret = 0; tx_cmd[0]=0x74; if( addr >= (1<<17) ) { err_ret = -1; goto goto_err; //return err_ret; } else { tx_cmd[1]=0x10|0x00|(addr>>15); tx_cmd[2]=addr>>7; tx_cmd[3]=( addr<<1 ); tx_cmd[4]= 0x00; } tx_cmd[5]=0x01; sif_spi_write_raw(spi, tx_cmd,6); //printf("CMD52 Read \n"); #if 0 //Response read sif_spi_read_raw(spi, rx_cmd,20); esp_dbg(ESP_DBG_ERROR, "write resp:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_cmd[0],rx_cmd[1] ,rx_cmd[2],rx_cmd[3],rx_cmd[4],rx_cmd[5],rx_cmd[6],rx_cmd[7],rx_cmd[8],rx_cmd[9]); return 0; #else //Read Response. do { rx_cmd[0]=0xFF; sif_spi_read_raw(spi, rx_cmd,1); }while(rx_cmd[0]==0xFF); rx_cmd[1]=0xFF; sif_spi_read_raw(spi, rx_cmd+1,1); esp_dbg(ESP_DBG_ERROR, "read resp:[0x%02x],[0x%02x]\n",rx_cmd[0],rx_cmd[1]); if(rx_cmd[0]!=0) err_ret = -1; else err_ret = 0; *value = rx_cmd[1]; //return err_ret; #endif goto_err: return err_ret; } int sif_spi_write_reg(struct spi_device *spi, unsigned int addr, unsigned char value) { unsigned char tx_cmd[6]; unsigned char rx_cmd[20]; int err_ret = 0; tx_cmd[0]=0x74; if( addr >= (1<<17) ) { err_ret = -1; goto goto_err; //return err_ret; } else { tx_cmd[1]=0x90|0x00|(addr>>15); //0x94; tx_cmd[2]=addr>>7; tx_cmd[3]=( addr<<1 ); tx_cmd[4]= value; } tx_cmd[5]=0x01; sif_spi_write_raw(spi, tx_cmd,6); //printf("CMD52 stauts=16 \n"); #if 0 //memset(rx_cmd,0xFF,20); sif_spi_read_raw(spi, rx_cmd,20); esp_dbg(ESP_DBG_ERROR, "write resp:[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x],[0x%02x]\n", rx_cmd[0],rx_cmd[1] ,rx_cmd[2],rx_cmd[3],rx_cmd[4],rx_cmd[5],rx_cmd[6],rx_cmd[7],rx_cmd[8],rx_cmd[9]); return 0; #else do { rx_cmd[0]=0xFF; sif_spi_read_raw(spi, rx_cmd,1); }while(rx_cmd[0]==0xFF); rx_cmd[1]=0xFF; sif_spi_read_raw(spi, rx_cmd+1,1); if( rx_cmd[1]!=value ) { //printf("Write error,%X,%X", rx_cmd[0],rx_cmd[1]); esp_dbg(ESP_DBG_ERROR, "write resp:[0x%02x],[0x%02x]\n",rx_cmd[0],rx_cmd[1]); err_ret = -1; goto goto_err; } goto_err: return err_ret; #endif //Read Response. } static int spi_irq_thread(void *data) { struct spi_device *spi = (struct spi_device *)data; do { sif_dsr(spi); set_current_state(TASK_INTERRUPTIBLE); sif_platform_irq_mask(0); if (!kthread_should_stop()) schedule(); set_current_state(TASK_RUNNING); } while (!kthread_should_stop()); return 0; } int sif_setup_irq_thread(struct spi_device *spi) { sif_irq_thread = kthread_run(spi_irq_thread, spi, "kspiirqd/eagle"); if (IS_ERR(sif_irq_thread)) { esp_dbg(ESP_DBG_ERROR, "setup irq thread error!\n"); return -1; } return 0; } static irqreturn_t sif_irq_handler(int irq, void *dev_id) { sif_platform_irq_mask(1); if (sif_platform_is_irq_occur()) { wake_up_process(sif_irq_thread); } else { sif_platform_irq_mask(0); return IRQ_NONE; } return IRQ_HANDLED; } void sif_enable_irq(struct esp_pub *epub) { int err; struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; ASSERT(epub != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); mdelay(100); sif_platform_irq_init(); err = sif_setup_irq_thread(spi); if (err) { esp_dbg(ESP_DBG_ERROR, "%s setup sif irq failed\n", __func__); return; } /******************compat with other device in some shared irq system ********************/ #ifdef REQUEST_IRQ_SHARED #if defined(REQUEST_IRQ_RISING) err = request_irq(sif_platform_get_irq_no(), sif_irq_handler, IRQF_TRIGGER_RISING | IRQF_SHARED, "esp_spi_irq", spi); #elif defined(REQUEST_IRQ_FALLING) err = request_irq(sif_platform_get_irq_no(), sif_irq_handler, IRQF_TRIGGER_FALLING | IRQF_SHARED, "esp_spi_irq", spi); #elif defined(REQUEST_IRQ_LOWLEVEL) err = request_irq(sif_platform_get_irq_no(), sif_irq_handler, IRQF_TRIGGER_LOW | IRQF_SHARED, "esp_spi_irq", spi); #elif defined(REQUEST_IRQ_HIGHLEVEL) err = request_irq(sif_platform_get_irq_no(), sif_irq_handler, IRQF_TRIGGER_HIGH | IRQF_SHARED, "esp_spi_irq", spi); #else /* default */ err = request_irq(sif_platform_get_irq_no(), sif_irq_handler, IRQF_TRIGGER_LOW | IRQF_SHARED, "esp_spi_irq", spi); #endif /* TRIGGER MODE */ #else err = request_irq(sif_platform_get_irq_no(), sif_irq_handler, IRQF_TRIGGER_LOW, "esp_spi_irq", spi); #endif /* ESP_IRQ_SHARED */ if (err) { esp_dbg(ESP_DBG_ERROR, "sif %s failed\n", __func__); return ; } atomic_set(&sctrl->irq_installed, 1); } void sif_disable_irq(struct esp_pub *epub) { int i = 0; struct esp_spi_ctrl *sctrl = NULL; struct spi_device *spi = NULL; ASSERT(epub != NULL); sctrl = (struct esp_spi_ctrl *)epub->sif; spi = sctrl->spi; ASSERT(spi != NULL); if (atomic_read(&sctrl->irq_installed) == 0) return; while (atomic_read(&sctrl->irq_handling)) { schedule_timeout(HZ / 100); if (i++ >= 400) { esp_dbg(ESP_DBG_ERROR, "%s force to stop irq\n", __func__); break; } } free_irq(sif_platform_get_irq_no(), spi); kthread_stop(sif_irq_thread); sif_platform_irq_deinit(); atomic_set(&sctrl->irq_installed, 0); } int esp_setup_spi(struct spi_device *spi) { /**** alloc buffer for spi io */ if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT) { buf_addr = (unsigned char *)kmalloc (MAX_BUF_SIZE, GFP_KERNEL); if (buf_addr == NULL) return -ENOMEM; tx_cmd = buf_addr; rx_cmd = buf_addr; } #if 0 spi->mode = 0x03; spi->bits_per_word = 8; spi->max_speed_hz = SPI_FREQ; return spi_setup(spi); #endif return 0; } static int esp_spi_probe(struct spi_device *spi); static int esp_spi_remove(struct spi_device *spi); static int esp_spi_probe(struct spi_device *spi) { int err; struct esp_pub *epub; struct esp_spi_ctrl *sctrl; esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__); err = esp_setup_spi(spi); if (err) { esp_dbg(ESP_DBG_ERROR, "%s setup_spi error[%d]\n", __func__, err); goto _err_spi; } esp_dbg(ESP_DBG_ERROR, "%s init_protocol\n", __func__); sif_spi_protocol_init(spi); if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){ sctrl = kzalloc(sizeof(struct esp_spi_ctrl), GFP_KERNEL); if (sctrl == NULL) { assert(0); return -ENOMEM; } /* temp buffer reserved for un-dma-able request */ sctrl->dma_buffer = kzalloc(ESP_DMA_IBUFSZ, GFP_KERNEL); if (sctrl->dma_buffer == NULL) { assert(0); goto _err_last; } sif_sctrl = sctrl; sctrl->slc_blk_sz = SIF_SLC_BLOCK_SIZE; epub = esp_pub_alloc_mac80211(&spi->dev); if (epub == NULL) { esp_dbg(ESP_DBG_ERROR, "no mem for epub \n"); err = -ENOMEM; goto _err_dma; } epub->sif = (void *)sctrl; sctrl->epub = epub; #ifdef USE_EXT_GPIO err = ext_gpio_init(epub); if (err) { esp_dbg(ESP_DBG_ERROR, "ext_irq_work_init failed %d\n", err); return err; } #endif } else { ASSERT(sif_sctrl != NULL); sctrl = sif_sctrl; sif_sctrl = NULL; epub = sctrl->epub; SET_IEEE80211_DEV(epub->hw, &spi->dev); epub->dev = &spi->dev; } epub->sdio_state = sif_sdio_state; sctrl->spi = spi; spi_set_drvdata(spi, sctrl); if (err){ if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT) goto _err_epub; else goto _err_second_init; } check_target_id(epub); #ifdef SDIO_TEST sif_test_tx(sctrl); #else err = esp_pub_init_all(epub); if (err) { esp_dbg(ESP_DBG_ERROR, "esp_init_all failed: %d\n", err); if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){ err = 0; goto _err_first_init; } if(sif_sdio_state == ESP_SDIO_STATE_SECOND_INIT) goto _err_second_init; } #endif //SDIO_TEST esp_dbg(ESP_DBG_TRACE, " %s return %d\n", __func__, err); if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){ esp_dbg(ESP_DBG_ERROR, "first normal exit\n"); sif_sdio_state = ESP_SDIO_STATE_FIRST_NORMAL_EXIT; up(&esp_powerup_sem); } return err; _err_epub: esp_pub_dealloc_mac80211(epub); _err_dma: kfree(sctrl->dma_buffer); _err_last: kfree(sctrl); _err_spi: if (buf_addr) { kfree(buf_addr); buf_addr = NULL; tx_cmd = NULL; rx_cmd = NULL; } _err_first_init: if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){ esp_dbg(ESP_DBG_ERROR, "first error exit\n"); sif_sdio_state = ESP_SDIO_STATE_FIRST_ERROR_EXIT; up(&esp_powerup_sem); } return err; _err_second_init: sif_sdio_state = ESP_SDIO_STATE_SECOND_ERROR_EXIT; esp_spi_remove(spi); return err; } static int esp_spi_remove(struct spi_device *spi) { struct esp_spi_ctrl *sctrl = NULL; sctrl = spi_get_drvdata(spi); if (sctrl == NULL) { esp_dbg(ESP_DBG_ERROR, "%s no sctrl\n", __func__); return -EINVAL; } do { if (sctrl->epub == NULL) { esp_dbg(ESP_DBG_ERROR, "%s epub null\n", __func__); break; } sctrl->epub->sdio_state = sif_sdio_state; if(sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT){ do{ int err; sif_lock_bus(sctrl->epub); err = sif_interrupt_target(sctrl->epub, 7); sif_unlock_bus(sctrl->epub); }while(0); if (sctrl->epub->sip) { sip_detach(sctrl->epub->sip); sctrl->epub->sip = NULL; esp_dbg(ESP_DBG_TRACE, "%s sip detached \n", __func__); #ifdef USE_EXT_GPIO ext_gpio_deinit(); #endif } } else { //sif_disable_target_interrupt(sctrl->epub); atomic_set(&sctrl->epub->sip->state, SIP_STOP); sif_disable_irq(sctrl->epub); } #ifdef TEST_MODE test_exit_netlink(); #endif /* TEST_MODE */ if(sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT){ esp_pub_dealloc_mac80211(sctrl->epub); esp_dbg(ESP_DBG_TRACE, "%s dealloc mac80211 \n", __func__); if (sctrl->dma_buffer) { kfree(sctrl->dma_buffer); sctrl->dma_buffer = NULL; esp_dbg(ESP_DBG_TRACE, "%s free dma_buffer \n", __func__); } kfree(sctrl); if (buf_addr) { kfree(buf_addr); buf_addr = NULL; rx_cmd = NULL; tx_cmd = NULL; } } } while (0); spi_set_drvdata(spi,NULL); esp_dbg(ESP_DBG_TRACE, "eagle spi remove complete\n"); return 0; } static int esp_spi_suspend(struct device *dev) { return 0; } static int esp_spi_resume(struct device *dev) { esp_dbg(ESP_DBG_ERROR, "%s", __func__); return 0; } static const struct dev_pm_ops esp_spi_pm_ops = { .suspend= esp_spi_suspend, .resume= esp_spi_resume, }; extern struct spi_device_id esp_spi_id[]; struct spi_driver esp_spi_driver = { .id_table = esp_spi_id, .driver = { .name = "eagle", .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = esp_spi_probe, .remove = esp_spi_remove, }; static int esp_spi_dummy_probe(struct spi_device *spi) { esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__); up(&esp_powerup_sem); return 0; } static int esp_spi_dummy_remove(struct spi_device *spi) { return 0; } struct spi_driver esp_spi_dummy_driver = { .id_table = esp_spi_id, .driver = { .name = "eagle_dummy", .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = esp_spi_dummy_probe, .remove = esp_spi_dummy_remove, }; static int __init esp_spi_init(void) { #define ESP_WAIT_UP_TIME_MS 11000 int err; u64 ver; int retry = 3; bool powerup = false; int edf_ret = 0; esp_dbg(ESP_DBG_TRACE, "%s \n", __func__); #ifdef REGISTER_SPI_BOARD_INFO sif_platform_register_board_info(); #endif #ifdef DRIVER_VER ver = DRIVER_VER; esp_dbg(ESP_SHOW, "\n*****%s %s EAGLE DRIVER VER:%llx*****\n\n", __DATE__, __TIME__, ver); #endif edf_ret = esp_debugfs_init(); #ifdef ANDROID android_request_init_conf(); #endif /* defined(ANDROID)*/ esp_wakelock_init(); esp_wake_lock(); do { sema_init(&esp_powerup_sem, 0); sif_platform_target_poweron(); err = spi_register_driver(&esp_spi_dummy_driver); if (err) { esp_dbg(ESP_DBG_ERROR, "eagle spi driver registration failed, error code: %d\n", err); goto _fail; } if (down_timeout(&esp_powerup_sem, msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) == 0) { powerup = true; msleep(200); break; } esp_dbg(ESP_SHOW, "%s ------ RETRY ------ \n", __func__); sif_record_retry_config(); spi_unregister_driver(&esp_spi_dummy_driver); sif_platform_target_poweroff(); } while (retry--); if (!powerup) { esp_dbg(ESP_DBG_ERROR, "eagle spi can not power up!\n"); err = -ENODEV; goto _fail; } esp_dbg(ESP_SHOW, "%s power up OK\n", __func__); spi_unregister_driver(&esp_spi_dummy_driver); sif_sdio_state = ESP_SDIO_STATE_FIRST_INIT; sema_init(&esp_powerup_sem, 0); spi_register_driver(&esp_spi_driver); if (down_timeout(&esp_powerup_sem, msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) == 0) { if(sif_sdio_state == ESP_SDIO_STATE_FIRST_NORMAL_EXIT){ spi_unregister_driver(&esp_spi_driver); msleep(80); sif_sdio_state = ESP_SDIO_STATE_SECOND_INIT; spi_register_driver(&esp_spi_driver); } } esp_register_early_suspend(); esp_wake_unlock(); return err; _fail: esp_wake_unlock(); esp_wakelock_destroy(); return err; } static void __exit esp_spi_exit(void) { esp_dbg(ESP_DBG_TRACE, "%s \n", __func__); esp_debugfs_exit(); esp_unregister_early_suspend(); spi_unregister_driver(&esp_spi_driver); #ifndef FPGA_DEBUG sif_platform_target_poweroff(); #endif /* !FPGA_DEBUG */ esp_wakelock_destroy(); } MODULE_AUTHOR("Espressif System"); MODULE_DESCRIPTION("Driver for SPI interconnected eagle low-power WLAN devices"); MODULE_LICENSE("GPL"); #endif /* ESP_USE_SPI */