/* * Function starts Read and write operation and transfers received data to TTY core. It pulls down MRDY signal * in case of single frame transfer then sets "ifx_read_write_completion" to indicate transfer complete. */ static void ifx_spi_send_and_receive_data(struct ifx_spi_data *spi_data) { unsigned int rx_valid_buf_size; int status = 0; status = ifx_spi_sync_read_write(spi_data, ifx_current_frame_size+IFX_SPI_HEADER_SIZE); /* 4 bytes for header */ if(status > 0){ #if defined(LGE_DUMP_SPI_BUFFER) dump_spi_buffer("ifx_spi_send_and_receive_data()[Trans]", &(ifx_tx_buffer[4]), COL_SIZE); #elif defined(LGE_VT_DATA_DUMP) dump_spi_wr_buffer(&(ifx_tx_buffer[4]), ifx_valid_frame_size + 4); #endif memset(ifx_tx_buffer,0,IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE); ifx_ret_count = ifx_ret_count + ifx_valid_frame_size; } // hgahn if(memcmp(rx_dummy, ifx_rx_buffer, IFX_SPI_HEADER_SIZE) ==0) { ifx_receiver_buf_size = 0; return; } /* Handling Received data */ ifx_receiver_buf_size = ifx_spi_get_header_info(&rx_valid_buf_size); // hgahn if((spi_data->throttle == 0) && (rx_valid_buf_size != 0) && !(spi_data->ifx_spi_lock)){ #ifdef LGE_DUMP_SPI_BUFFER dump_spi_buffer("ifx_spi_send_and_receive_data()[Recev]", &(ifx_rx_buffer[4]), COL_SIZE); #elif defined(LGE_VT_DATA_DUMP) //dump_spi_rd_buffer(&(ifx_rx_buffer[4]), rx_valid_buf_size-2); /* MUX에서의 Ctrl & Flag Byte 제거 */ #endif tty_insert_flip_string(spi_data->ifx_tty, ifx_rx_buffer+IFX_SPI_HEADER_SIZE, rx_valid_buf_size); tty_flip_buffer_push(spi_data->ifx_tty); } /*else { handle RTS and CTS in SPI flow control Reject the packet as of now }*/ }
/* * Function starts Read and write operation and transfers received data to TTY core. It pulls down MRDY signal * in case of single frame transfer then sets "ifx_read_write_completion" to indicate transfer complete. */ static void ifx_spi_send_and_receive_data(struct ifx_spi_data *spi_data) { unsigned int rx_valid_buf_size; int status = 0; int recieve_copied ; IFX_SPI_DEBUG(" curr frame size = %d, total size=%d\n ", spi_data->ifx_current_frame_size, spi_data->ifx_current_frame_size+IFX_SPI_HEADER_SIZE) ; status = ifx_spi_sync_read_write(spi_data, spi_data->ifx_current_frame_size+IFX_SPI_HEADER_SIZE); /* 4 bytes for header */ IFX_SPI_DEBUG("status = %d ", status); #ifdef IFX_SPI_DUMP_LOG IFX_SPI_PRINTK("SPI TX ----------------- "); ifx_dump_atcmd(spi_data->ifx_tx_buffer+IFX_SPI_HEADER_SIZE+2); #endif if(status > 0) { memset(spi_data->ifx_tx_buffer,0,IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE); spi_data->ifx_ret_count = spi_data->ifx_ret_count + spi_data->ifx_valid_frame_size; } //ifx modem에서만 rx buf에 data 없으면 return... if (*((int*)spi_data->ifx_rx_buffer) == 0xFFFFFFFF) { spi_data->ifx_receiver_buf_size = 0; IFX_SPI_DEBUG("received data is nothing.."); return; } /* Handling Received data */ spi_data->ifx_receiver_buf_size = ifx_spi_get_header_info(spi_data->ifx_rx_buffer, &rx_valid_buf_size); // spi에서 rx data가 존재하면 tty 로 전송 if((spi_data->throttle == 0) && (rx_valid_buf_size != 0)) { if(spi_data->ifx_tty) { #if defined(LGE_DUMP_SPI_BUFFER) dump_spi_buffer("SPI RX", &spi_data->ifx_rx_buffer[4], COL_SIZE); #endif #ifdef IFX_SPI_DUMP_LOG IFX_SPI_PRINTK("SPI RX ----------------- "); ifx_dump_atcmd(spi_data->ifx_rx_buffer+IFX_SPI_HEADER_SIZE+2) ; #endif /* spi에서 rx data가 존재하면 tty 로 전송 */ #ifdef IFX_SPI_SPEED_MEASUREMENT uiRxlen[spi_data->ifx_tty->index] = rx_valid_buf_size+IFX_SPI_HEADER_SIZE; #endif recieve_copied = tty_insert_flip_string(spi_data->ifx_tty, (spi_data->ifx_rx_buffer+IFX_SPI_HEADER_SIZE), rx_valid_buf_size); // if(recieve_copied) tty_flip_buffer_push(spi_data->ifx_tty); //else // printk("tty_insert_flip_string err") ; } else { IFX_SPI_DEBUG("no tty err ") ; } } /*else { handle RTS and CTS in SPI flow control Reject the packet as of now }*/ #ifdef WAKE_LOCK_RESUME if(spi_data->wake_lock_flag) { spi_data->wake_lock_flag = 0; } #endif }
static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct ifx_spi_data *spi_data = (struct ifx_spi_data *)tty->driver_data; if(spi_data==NULL) { IFX_SPI_PRINTK("failed : spi_data is null"); return 0; } // spi suspend check and spi_tegra suspend check if(spi_data->is_suspended ||spi_tegra_is_suspend(spi_data->spi)) { IFX_SPI_PRINTK("SPI suspend : %d, SPI Tegra suspend : %d",spi_data->is_suspended,spi_tegra_is_suspend(spi_data->spi)); return -1; } spi_data->ifx_ret_count = 0; spi_data->ifx_tty = tty; spi_data->ifx_tty->low_latency = 1; #ifdef IFX_SPI_SPEED_MEASUREMENT int id = tty->index; // spi no. unsigned long diff; fWrite[id] = 1; uiTxlen[id] = count + IFX_SPI_HEADER_SIZE; //ulStart = getuSecTime(); do_gettimeofday(&ulStart[id]); //RTC(Real Time Clock)의 현재 실행시간 #endif if( !buf ) { IFX_SPI_PRINTK("\t Buffer NULL"); return spi_data->ifx_ret_count; } if(!count) { IFX_SPI_PRINTK("\t Count is ZERO"); return spi_data->ifx_ret_count; } IFX_SPI_DEBUG("**** \n"); #ifdef LGE_DUMP_SPI_BUFFER dump_spi_buffer("ifx_spi_write()", buf, count); #endif spi_data->ifx_master_initiated_transfer = 1; spi_data->ifx_spi_buf = buf; spi_data->ifx_spi_count = count; ifx_spi_set_mrdy_signal(1); wait_for_completion_timeout(&spi_data->ifx_read_write_completion, 2*HZ); //3ms -> 500ms //To check the spi retry count when data transmit.. if(spi_data->ifx_ret_count == 0) { int pin_val; pin_val = gpio_get_value(IFX_SRDY); ifx_spi_set_mrdy_signal(0); IFX_SPI_PRINTK("spi tx timeout!! SRDY : %d , buf : 0x%x, count : %d",pin_val,buf,count); IFX_SPI_PRINTK("ifx_master_initiated_transfer : %d, is_suspended : %d, tegra_suspend : %d", spi_data->ifx_master_initiated_transfer,spi_data->is_suspended,spi_tegra_is_suspend(spi_data->spi)); #ifdef LGE_DUMP_SPI_BUFFER ifx_dump_spi_buffer("ifx_spi_write -- fail()", buf, count); #endif init_completion(&spi_data->ifx_read_write_completion); return -2; /* To Check error */ } #ifdef IFX_SPI_SPEED_MEASUREMENT //ulEnd = getuSecTime() - ulStart; do_gettimeofday(&ulEnd[id]); diff = (ulEnd[id].tv_sec - ulStart[id].tv_sec) * 1000 * 1000; //sec diff = (diff + (ulEnd[id].tv_usec - ulStart[id].tv_usec)); ulTxThroughtput[id] = ((uiTxlen[id]*8*1000)/diff); IFX_SPI_PRINTK(" [SPI %d] : TX time = %09d usec; %04d bytes; %06lu Kbps", id, diff, IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE, ((IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE)*8*1000)/diff); uiTxlen[id]; fWrite[id] = 0; #endif init_completion(&spi_data->ifx_read_write_completion); return spi_data->ifx_ret_count; /* Number of bytes sent to the device */ }
static unsigned int ifx_spi_sync_read_write(struct ifx_spi_data *spi_data, unsigned int len) { bool spi_suspend_failed; int status; int ipc_check; struct spi_message m; struct spi_transfer t = { .tx_buf = spi_data->ifx_tx_buffer, .rx_buf = spi_data->ifx_rx_buffer, .len = len, }; #ifdef IFX_SPI_TEGRA_TRANSFER_DURATION static struct timeval transfer_start_time; static struct timeval transfer_end_time; unsigned long duration_time; #endif spi_message_init(&m); spi_message_add_tail(&t, &m); IFX_SPI_DEBUG(""); if (spi_data->spi == NULL) { IFX_SPI_PRINTK("spi_data->spi = NULL"); status = -ESHUTDOWN; } else { #ifdef IFX_SPI_TEGRA_TRANSFER_DURATION IFX_SPI_PRINTK("!!! spi_transfer start !!!"); do_gettimeofday(&transfer_start_time); status = spi_sync(spi_data->spi, &m); do_gettimeofday(&transfer_end_time); duration_time = (transfer_end_time.tv_usec - transfer_start_time.tv_usec); //sec IFX_SPI_PRINTK("!!! spi_transfer end is %06d ms !!!", (duration_time/1000)); //milisec #else status = spi_sync(spi_data->spi, &m); #endif } if (status == 0) { status = m.status; if (status == 0) { status = m.actual_length; } //reset 'count_transfer_failed' to zero, if spi transter succeeds at least one out of five times count_transfer_failed = 0; } else { ipc_check = ifx_modem_communicating(); if(ipc_check == 0) { IFX_SPI_PRINTK("transmission unsuccessful, [spi_sync] status:%d, count_Failed:%d\n", status, count_transfer_failed); spi_suspend_failed = spi_tegra_suspend_failed(spi_data->spi); if (spi_suspend_failed) { IFX_SPI_PRINTK("kernel_restart!!!, spi_suspend_failed=%d \n", spi_suspend_failed); kernel_restart(NULL); } } //increase 'count_transfer_failed', when spi transter fails count_transfer_failed++; } #ifdef IFX_SPI_TX_RX_BUF IFX_SPI_PRINTK("SPI TX BUFFER: "); for(i=0;i<16;i++) { printk( "%02x ",spi_data->ifx_tx_buffer[i]); } IFX_SPI_PRINTK("\n"); IFX_SPI_PRINTK("SPI RX BUFFER : "); for(i=0;i<16;i++) { printk( "%02x ",spi_data->ifx_rx_buffer[i]); } #endif return status; } /* * Function is a Interrupt service routine, is called when SRDY signal goes HIGH. It set up transmission and * reception if it is a Slave initiated data transfer. For both the cases Master intiated/Slave intiated * transfer it starts data transfer. */ static irqreturn_t ifx_spi_handle_srdy_irq(int irq, void *handle) { struct ifx_spi_data *spi_data = (struct ifx_spi_data *)handle; int pin_val; IFX_SPI_DEBUG(""); #ifdef IFX_TEGRA_EDGE_TRIGGER pin_val = gpio_get_value(IFX_SRDY); IFX_SPI_DEBUG("pin_val = %d", pin_val); if(pin_val == 0) { printk("[SPI][SRDY_IRQ] pin value is ZERO.. Return!! \n"); IFX_SPI_DEBUG(" IRQF_TRIGGER_FALLING in the srdy irq is ignore !!! \n"); return IRQ_HANDLED; } #endif #if 0 if(spi_data && spi_data->ifx_tty) //add to prevent the irq of srdy until spi opening { IFX_SPI_DEBUG("queue_work is done!"); queue_work(spi_data->ifx_wq, &spi_data->ifx_work); } else { IFX_SPI_PRINTK("Unexpected interrupt happen!"); IFX_SPI_PRINTK("spi_data = 0x%p, 0x%p, spi_data->ifx_tty =0x%p", spi_data, spi_data->ifx_tty); } #else #ifdef WAKE_LOCK_RESUME // HZ is 1sec IFX_SPI_DEBUG("[IFX_SRDY] wake lock : 0x%lx", &ifx_gspi_data->wake_lock); wake_lock_timeout(&ifx_gspi_data->wake_lock, msecs_to_jiffies(500)); //5,, Unexpected interrupt or power consumption #endif IFX_SPI_DEBUG("queue_work is done!"); queue_work(spi_data->ifx_wq, &spi_data->ifx_work); #endif return IRQ_HANDLED; } // ifx_master_initiated_transfer = 1; --> set called by ifx_spi_write() // ifx_master_initiated_transfer = 0; --> default static void ifx_spi_handle_work(struct work_struct *work) { bool spi_tegra_suspended; struct ifx_spi_data *spi_data = container_of(work, struct ifx_spi_data, ifx_work); #ifdef IFX_SPI_SPEED_MEASUREMENT int id = 0; unsigned long diff; #endif IFX_SPI_DEBUG( " start"); // 20120904 jisil.park unsigned long reg; int pm_off_count; if(1 == spi_data->is_suspended) { pm_off_count = 1; printk("[SPI][handle_work] ifx_spi_handle_work INFO spi_data->is_suspended is (0x%x)\n", spi_data->is_suspended); //wait for ap to return to resume state with a worst case scenario of 5sec do { mdelay(1); pm_off_count++; }while((1 == spi_data->is_suspended) && (pm_off_count<(5*200))); printk("[EBS] ifx_spi_handle_work INFO EXIT is_suspend = 0x%x pm_off_count=%d\n", spi_data->is_suspended, pm_off_count); if(1 == spi_data->is_suspended) { // To Do how to handle the PM OFF state during 1sec printk("[SPI][handle_work] ifx_spi_handle_work error is_suspended is (0x%x)\n",spi_data->is_suspended); } } // 20120904 jisil.park /* add to wait tx/rx data when tegra spi is suspended*/ spi_tegra_suspended = spi_tegra_is_suspend(spi_data->spi); if (spi_tegra_suspended) { IFX_SPI_PRINTK("spi_tegra is not resume !, spi_tegra_suspended = %d\n",spi_tegra_suspended); return; } if (!spi_data->ifx_master_initiated_transfer) { IFX_SPI_TX_DEBUG("CP Start =================> \n"); #ifdef IFX_SPI_SPEED_MEASUREMENT do_gettimeofday(&ulStart[id]); #endif ifx_spi_setup_transmission(spi_data); ifx_spi_set_mrdy_signal(1); ifx_spi_send_and_receive_data(spi_data); #ifdef IFX_SPI_SPEED_MEASUREMENT do_gettimeofday(&ulEnd[id]); diff = (ulEnd[id].tv_sec - ulStart[id].tv_sec) * 1000 * 1000 ; diff = (diff + (ulEnd[id].tv_usec - ulStart[id].tv_usec)); ulRxThroughtput[id] = ((uiRxlen[id]*8*1000)/diff); IFX_SPI_PRINTK("[SPI %d] : RX time = %09d usec; %04d bytes; %06lu Kbps", id, diff, IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE, ((IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE)*8*1000)/diff); #endif /* Once data transmission is completed, the MRDY signal is lowered */ if((spi_data->ifx_sender_buf_size == 0) && (spi_data->ifx_receiver_buf_size == 0)) { ifx_spi_set_mrdy_signal(0); ifx_spi_buffer_initialization(spi_data); } /* We are processing the slave initiated transfer in the mean time Mux has requested master initiated data transfer */ /* Once Slave initiated transfer is complete then start Master initiated transfer */ if(spi_data->ifx_master_initiated_transfer == 1) //why check ? already ifx_master_initiated_transfer = 0 { /* It is a condition where Slave has initiated data transfer and both SRDY and MRDY are high and at the end of data transfer * MUX has some data to transfer. MUX initiates Master initiated transfer rising MRDY high, which will not be detected at Slave-MODEM. * So it was required to rise MRDY high again */ udelay(MRDY_DELAY_TIME) ; ifx_spi_set_mrdy_signal(1); } IFX_SPI_TX_DEBUG("CP End =================> \n"); } else { IFX_SPI_TX_DEBUG("Interrupt by AP25 ===========> \n"); ifx_spi_setup_transmission(spi_data); #if defined(LGE_DUMP_SPI_BUFFER) dump_spi_buffer("SPI TX", &spi_data->ifx_tx_buffer[4], COL_SIZE); #endif ifx_spi_send_and_receive_data(spi_data); /* Once data transmission is completed, the MRDY signal is lowered */ if(spi_data->ifx_sender_buf_size == 0) { if(spi_data->ifx_receiver_buf_size == 0) { ifx_spi_set_mrdy_signal(0); udelay(MRDY_DELAY_TIME) ; ifx_spi_buffer_initialization(spi_data); } IFX_SPI_TX_DEBUG("ifx_master_initiated_transfer set = 0 <============== \n"); spi_data->ifx_master_initiated_transfer = 0; complete(&spi_data->ifx_read_write_completion); } } #ifdef IFX_SPI_TX_RX_THROUGHTPUT if(uiTxlen[spi_data->mdm_tty->index] || uiRxlen[spi_data->mdm_tty->index]) { //ulEnd = getuSecTime() - ulStart; do_gettimeofday(&ulEnd[spi_data->ifx_tty->index]); uidiff[spi_data->ifx_tty->index] = (ulEnd[spi_data->ifx_tty->index].tv_sec - ulStart[spi_data->ifx_tty->index].tv_sec) * 1000 * 1000 ; uidiff[spi_data->ifx_tty->index] = uidiff[spi_data->ifx_tty->index] + (ulEnd[spi_data->ifx_tty->index].tv_usec - ulStart[spi_data->ifx_tty->index].tv_usec); ulTxThroughtput[spi_data->ifx_tty->index] = ((uiTxlen[spi_data->ifx_tty->index]*8*1000)/uidiff[spi_data->ifx_tty->index]); ulRxThroughtput[spi_data->ifx_tty->index] = ((uiRxlen[spi_data->ifx_tty->index]*8*1000)/uidiff[spi_data->ifx_tty->index]); IFX_SPI_PRINTK("[SPI %d] time = %d us, Tx(%dbytes) = %luKbps, Rx(%dbytes) = %luKbps, Max(%dbytes) = %luKbps\n", spi_data->ifx_tty->index, uidiff[spi_data->mdm_tty->index], uiTxlen[spi_data->ifx_tty->index], ulTxThroughtput[spi_data->ifx_tty->index], uiRxlen[spi_data->ifx_tty->index], ulRxThroughtput[spi_data->ifx_tty->index], IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE, ((IFX_SPI_MAX_BUF_SIZE+IFX_SPI_HEADER_SIZE)*8*1000)/uidiff[spi_data->ifx_tty->index]); uiTxlen[spi_data->ifx_tty->index] = uiRxlen[spi_data->ifx_tty->index] = 0; fWrite[spi_data->ifx_tty->index] = 0; } #endif IFX_SPI_DEBUG( " end"); }
static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct ifx_spi_data *spi_data = (struct ifx_spi_data *)tty->driver_data; ifx_ret_count = 0; #ifdef LGE_DUMP_SPI_BUFFER dump_spi_buffer("ifx_spi_write()", buf, count); #elif defined(LGE_VT_DATA_DUMP) if (count == 167) // 167 means 160(MUX data) + 7 (DLC Frame Header + Tails) { // dump_spi_wr_buffer(buf, count); } #endif // hgahn if(spi_data->ifx_spi_lock) return ifx_ret_count; spi_data->ifx_tty = tty; spi_data->ifx_tty->low_latency = 1; if( !buf ){ printk("File: ifx_n721_spi.c\tFunction: int ifx_spi_write()\t Buffer NULL\n"); return ifx_ret_count; } if(!count){ printk("File: ifx_n721_spi.c\tFunction: int ifx_spi_write()\t Count is ZERO\n"); return ifx_ret_count; } ifx_master_initiated_transfer = 1; ifx_spi_buf = buf; ifx_spi_count = count; // LGE_CHANGE_S [[email protected]] 2010-10-11 to retry IPC transmission when SRDY is not signaled by CP /* original code ifx_spi_set_mrdy_signal(1); wait_for_completion(&spi_data->ifx_read_write_completion); */ { int i, max_retry_count=8; unsigned long timeout=HZ; long rc; for (i=0 ; i<max_retry_count ; i++) { // signal master ready ifx_spi_set_mrdy_signal(1); // wait for completion with timeout rc = wait_for_completion_timeout( &spi_data->ifx_read_write_completion, timeout); if (rc == 0) { // timeout expired, retry printk("***** unable to detect SREADY within %lu, RETRY (counter=%d) *****\n", timeout, i+1); // lower master ready ifx_spi_set_mrdy_signal(0); //<*****@*****.**> LGE_CHANGE_S ril_retry_count if(i == (max_retry_count-1)) { { set_modem_alive(0); ifx_ril_is_modem_alive = 0; } } //<*****@*****.**> LGE_CHANGE_E ril_retry_count // retry after delay udelay(100); // 20 u sec delay } else { // success or failure //printk("wait_for_completion_timeout timeout=%ld\n", timeout); //<*****@*****.**> LGE_CHANGE_S ril_retry_count if(!ifx_ril_is_modem_alive) { set_modem_alive(1); ifx_ril_is_modem_alive = 1; } //<*****@*****.**> LGE_CHANGE_E ril_retry_count break; } } } // LGE_CHANGE_E [[email protected]] 2010-10-11 to retry IPC transmission when SRDY is not signaled by CP init_completion(&spi_data->ifx_read_write_completion); return ifx_ret_count; /* Number of bytes sent to the device */ }