u32 sdhci_disconnect(u32  status)
{
	DBG("[SDIO_IPC]sdhci_disconnect: %s\r\n", status ? "SDHCI_TRANSFER_ERROR" : "SDHCI_TRANSFER_OK");
	_DisableSleep();
#ifdef SDHCI_RESEND_SUPPORT
	if(SDHCI_TRANSFER_OK  == status)
	{
		set_ap_status();	/* success */
	}
	else
	{
		clear_ap_status();/* fail */
	}

         ap2cp_rts_disable();/* end */

	if(!wait_event_timeout(s_gpio_cp_ready_wq, !cp2ap_rdy(), MAX_MIPC_WAIT_TIMEOUT/HZ))
	{
		printk("[MIPC] SDIO Disconnect Timeout!\r\n");
		return	SDHCI_TIMEOUT;
	}
#else
	 ap2cp_rts_disable();/* end */
#endif

	return   SDHCI_SUCCESS;
}
u32 sdhci_connect(u32   direction)
{
	_DisableSleep();
	if(SDHCI_TRANSFER_DIRECT_WRITE == direction)
	{
	          clear_ap_status();	/* send */
	}
	else
	{
		set_ap_status();	/* receive */
	}

	ap2cp_rts_enable(); 	/* start */

	if(!wait_event_timeout(s_gpio_cp_ready_wq, cp2ap_rdy(), MAX_MIPC_WAIT_TIMEOUT/HZ))
	{
		printk("[MIPC] SDIO %s Connect Timeout!\r\n", direction ? "Read" : "Write" );
		return	SDHCI_TIMEOUT;
	}
	return  SDHCI_SUCCESS;
}
static int mux_ipc_rx_thread(void *data)
{
        struct sched_param	 param = {.sched_priority = 25};
        printk(KERN_INFO "mux_ipc_rx_thread enter\r\n");
        sched_setscheduler(current, SCHED_FIFO, &param);

        wait_cp_bootup();
        msleep(500);

        printk(KERN_INFO "mux_ipc_rx_thread start----\r\n");
        //check CP status when start up
        if(0 == cp2ap_rdy()) {
                s_mipc_rx_event_flags = 1;
        }
        //working loop
        while (!kthread_should_stop()) {
                wait_event(s_mux_ipc_rx_wq,  s_mipc_rx_event_flags);
                process_modem_packet(0);
        }

        return 0;
}

static int mux_ipc_create_rx_thread(void)
{
        printk("mux_ipc_rx_create_thread enter.\n");
        init_waitqueue_head(&s_mux_ipc_rx_wq);
        s_mux_ipc_rx_thread = kthread_create(mux_ipc_rx_thread, NULL, "mipc_rx_thread");

        if (IS_ERR(s_mux_ipc_rx_thread)) {
                printk("ipc_sdio.c:mux_ipc_rx_thread error!.\n");
                return -1;
        }

        wake_up_process(s_mux_ipc_rx_thread);

        return 0;
}
static int mux_ipc_sdio_thread(void *data)
{
        int rval;
        struct sched_param	 param = {.sched_priority = 35};
        u32							continue_tx_cnt = 0;
        printk(KERN_INFO "mux_ipc_sdio_thread enter\r\n");
        sched_setscheduler(current, SCHED_FIFO, &param);


        sdhci_hal_gpio_init();

        //while(1) msleep(500);
        wait_cp_bootup();
        do {
                rval = sprd_sdio_channel_open();
                printk(KERN_INFO "%s() sdio channel opened %d\n", __func__, rval);
        } while(rval);

        sdhci_hal_gpio_irq_init();

        printk(KERN_INFO "mux_ipc_sdio_thread start----\r\n");
        while (!kthread_should_stop()) {
                bool force_tx = false;

                wait_event_timeout(s_mux_ipc_sdio_wq, (s_mipc_rx_req_flag || MIPC_TX_REQ_FLAG),
                                   msecs_to_jiffies(MAX_SDIO_SLEEP_TIMEOUT));
                if(!(s_mipc_rx_req_flag || MIPC_TX_REQ_FLAG)) {
                        //set ap inactive to let cp sleep
                        ap2cp_rts_enable();
                        set_cp_awake(false);

                        //wait for requests
                        wait_event(s_mux_ipc_sdio_wq,  (s_mipc_rx_req_flag || MIPC_TX_REQ_FLAG));
                }

                //got sdio request
                //check modem status
                if(!_is_mux_ipc_enable()) {
                        printk("[mipc] ipc reset free all tx data!\r\n");
                        _FreeAllTxTransferFrame();
                        while(!_is_mux_ipc_enable()) {
                                printk("mux ipc tx Thread Wait enable!\r\n");
                                msleep(40);
                        }
                        printk("mux ipc tx Thread Wait enable Finished!\r\n");
                }



                //make sure cp is awake
                if(!get_cp_awake()) {
                        ap2cp_rts_disable();

                        //wait cp ack
                        if(!wait_cp_awake(msecs_to_jiffies(MAX_SDIO_CP_ACK_TIMEOUT))) {
                                printk("[MIPC] SDIO wait cp awake fail!\r\n");

                                //cp no ack, just discard a request
                                ap2cp_rts_enable();
                                msleep(2);

                                continue;

                        }
                        set_cp_awake(true);
                        if(MIPC_TX_REQ_FLAG) {
                                force_tx = true;
                        }
                }

                //do rx first, if not force to do tx
                if(s_mipc_rx_req_flag && !force_tx) {
                        int result;

                        result = do_sdio_rx(&s_tx_flow_info, &s_acked_tx_frame);
                        s_mipc_rx_req_flag = 0;
                        continue_tx_cnt = 0;

                        if(SDHCI_TRANSFER_OK == result) {
                                if(s_mipc_tx_ctrl.last_ack_frame != s_acked_tx_frame) {
                                        ack_tx_frame_num(s_acked_tx_frame);
                                }

                                if(s_acked_tx_frame != s_last_tx_frame) {
                                        nack_tx_frame_num();
                                }

                                if(s_tx_flow_info == 0) {
                                        ipc_info_error_status(IPC_TX_CHANNEL, IPC_STATUS_FLOW_STOP);
                                }
                        }

                }

                //do tx
                if(MIPC_TX_REQ_FLAG) {

                        MIPC_TRANSF_FRAME_T* frame = get_from_sdio_tx_fifo();

                        if(frame) {
                                do_sdio_tx(frame);
                                continue_tx_cnt++;
                        }

                        force_tx = false;
                }

                //check cp read request after one cmd53
                if(0 == cp2ap_rdy()) {
                        continue_tx_cnt = 0;
                        if(have_buffer_to_read()) {
                                s_mipc_rx_req_flag = 1;
                        } else {
                                wake_up_mipc_rx_thread(1);
                        }
                }

                if(continue_tx_cnt >= 2) {
                        continue_tx_cnt--;
                        implicit_ack_tx_frame();
                }



        }

        return 0;
}

static int mux_ipc_create_sdio_thread(void)
{
        printk("mux_ipc_create_sdio_thread enter.\n");
        init_waitqueue_head(&s_mux_ipc_sdio_wq);
        s_mux_ipc_sdio_thread = kthread_create(mux_ipc_sdio_thread, NULL, "mipc_sdio_thread");

        if (IS_ERR(s_mux_ipc_sdio_thread)) {
                printk("ipc_sdio.c:s_mux_ipc_sdio_thread error!.\n");
                return -1;
        }

        wake_up_process(s_mux_ipc_sdio_thread);

        return 0;
}
static irqreturn_t cp_to_ap_rdy_handle(int irq, void *handle)
{
	DBG("[SDIO_IPC]cp_to_ap_rdy_handle:%d\r\n ", cp2ap_rdy());
	wake_up(&s_gpio_cp_ready_wq);
	return IRQ_HANDLED;
}