/*
 * Copyright (c) 2010 -2013 Espressif System.
 *
 *   sdio serial i/f driver
 *    - sdio device control routines
 *    - sync/async DMA/PIO read/write
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#ifdef ESP_USE_SDIO
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
#include <linux/module.h>
#include <net/mac80211.h>
#include <linux/time.h>
#include <linux/pm.h>

#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"
#include "esp_file.h"
#ifdef USE_EXT_GPIO
#include "esp_ext.h"
#endif /* USE_EXT_GPIO */

static int /*__init*/ esp_sdio_init(void);
static void  /*__exit*/ esp_sdio_exit(void);


#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_sdio_ctrl *sif_sctrl = NULL;

#ifdef ESP_ANDROID_LOGGER
bool log_off = false;
#endif /* ESP_ANDROID_LOGGER */

static int esdio_power_off(struct esp_sdio_ctrl *sctrl);
static int esdio_power_on(struct esp_sdio_ctrl *sctrl);

void sif_set_clock(struct sdio_func *func, int clk);

#include "sdio_stub.c"

void sif_lock_bus(struct esp_pub *epub)
{
        EPUB_FUNC_CHECK(epub, _exit);

        sdio_claim_host(EPUB_TO_FUNC(epub));
_exit:
	return;
}

void sif_unlock_bus(struct esp_pub *epub)
{
        EPUB_FUNC_CHECK(epub, _exit);

        sdio_release_host(EPUB_TO_FUNC(epub));
_exit:
	return;
}

static inline bool bad_buf(u8 * buf)
{
       return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
}

u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res)
{
        struct esp_sdio_ctrl *sctrl = NULL;
        struct sdio_func *func = NULL;
        sctrl = (struct esp_sdio_ctrl *)epub->sif;
        func = sctrl->func;

	if(func->num == 0)
        	return sdio_f0_readb(func, addr, res);
	else
        	return sdio_readb(func, addr, res);
}

void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res)
{
        struct esp_sdio_ctrl *sctrl = NULL;
        struct sdio_func *func = NULL;
        sctrl = (struct esp_sdio_ctrl *)epub->sif;
        func = sctrl->func;
	
	if(func->num == 0)
        	sdio_f0_writeb(func, value, addr, res);
	else
		sdio_writeb(func, value, addr, res);
	sif_platform_check_r1_ready(epub);
}

int sif_io_raw(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
{
        int err = 0;
        u8 *ibuf = NULL;
        bool need_ibuf = false;
        struct esp_sdio_ctrl *sctrl = NULL;
        struct sdio_func *func = NULL;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		err = -EINVAL;
		goto _exit;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;
        func = sctrl->func;
	if (func == NULL) {
		ESSERT(0);
		err = -EINVAL;
		goto _exit;
	}

        if (bad_buf(buf)) {
                esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n", __func__, addr, len);
                need_ibuf = true;
                ibuf = sctrl->dma_buffer;
        } else {
                ibuf = buf;
        }

        if (flag & SIF_BLOCK_BASIS) {
                /* round up for block data transcation */
        }

        if (flag & SIF_TO_DEVICE) {

                if (need_ibuf)
                        memcpy(ibuf, buf, len);

                if (flag & SIF_FIXED_ADDR)
                        err = sdio_writesb(func, addr, ibuf, len);
                else if (flag & SIF_INC_ADDR) {
                        err = sdio_memcpy_toio(func, addr, ibuf, len);
                }
                sif_platform_check_r1_ready(epub);
        } else if (flag & SIF_FROM_DEVICE) {

                if (flag & SIF_FIXED_ADDR)
                        err = sdio_readsb(func, ibuf, addr, len);
                else if (flag & SIF_INC_ADDR) {
                        err = sdio_memcpy_fromio(func, ibuf, addr, len);
                }


                if (!err && need_ibuf)
                        memcpy(buf, ibuf, len);
        }

_exit:
       return err;
}

int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
{
        int err = 0;
        u8 * ibuf = NULL;
        bool need_ibuf = false;
        struct esp_sdio_ctrl *sctrl = NULL;
        struct sdio_func *func = NULL;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		err = -EINVAL;
		goto _exit;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;
        func = sctrl->func;
	if (func == NULL) {
		ESSERT(0);	
		err = -EINVAL;
		goto _exit;
	}

        if (bad_buf(buf)) {
                esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n", __func__, addr, len);
                need_ibuf = true;
                ibuf = sctrl->dma_buffer;
        } else {
                ibuf = buf;
        }

        if (flag & SIF_BLOCK_BASIS) {
                /* round up for block data transcation */
        }

        if (flag & SIF_TO_DEVICE) {

                esp_dbg(ESP_DBG_TRACE, "%s to addr 0x%08x, len %d \n", __func__, addr, len);
                if (need_ibuf)
                        memcpy(ibuf, buf, len);

                sdio_claim_host(func);

                if (flag & SIF_FIXED_ADDR)
                        err = sdio_writesb(func, addr, ibuf, len);
                else if (flag & SIF_INC_ADDR) {
                        err = sdio_memcpy_toio(func, addr, ibuf, len);
                }
                sif_platform_check_r1_ready(epub);
                sdio_release_host(func);
        } else if (flag & SIF_FROM_DEVICE) {

                esp_dbg(ESP_DBG_TRACE, "%s from addr 0x%08x, len %d \n", __func__, addr, len);

                sdio_claim_host(func);

                if (flag & SIF_FIXED_ADDR)
                        err = sdio_readsb(func, ibuf, addr, len);
                else if (flag & SIF_INC_ADDR) {
                        err = sdio_memcpy_fromio(func, ibuf, addr, len);
                }

                sdio_release_host(func);

                if (!err && need_ibuf)
                        memcpy(buf, ibuf, len);
        }

_exit:
        return err;
}

int sif_lldesc_read_sync(struct esp_pub *epub, u8 *buf, u32 len)
{
        struct esp_sdio_ctrl *sctrl = NULL;
        u32 read_len;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		return -EINVAL;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;

        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_io_sync((epub), (sctrl->slc_window_end_addr - 2 - (len)), (buf), (read_len), SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}

int sif_lldesc_write_sync(struct esp_pub *epub, u8 *buf, u32 len)
{
        struct esp_sdio_ctrl *sctrl = NULL;
        u32 write_len;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		return -EINVAL;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;

        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_io_sync((epub), (sctrl->slc_window_end_addr - (len)), (buf), (write_len), SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}

int sif_lldesc_read_raw(struct esp_pub *epub, u8 *buf, u32 len, bool noround)
{
        struct esp_sdio_ctrl *sctrl = NULL;
        u32 read_len;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		return -EINVAL;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;

        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_io_raw((epub), (sctrl->slc_window_end_addr - 2 - (len)), (buf), (read_len), SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}

int sif_lldesc_write_raw(struct esp_pub *epub, u8 *buf, u32 len)
{
        struct esp_sdio_ctrl *sctrl = NULL;
        u32 write_len;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		return -EINVAL;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;

        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_io_raw((epub), (sctrl->slc_window_end_addr - (len)), (buf), (write_len), SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);

}

#define MANUFACTURER_ID_EAGLE_BASE        0x1110
#define MANUFACTURER_ID_EAGLE_BASE_MASK     0xFF00
#define MANUFACTURER_CODE                  0x6666

static const struct sdio_device_id esp_sdio_devices[] = {
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_EAGLE_BASE | 0x1))},
        {},
};

static int esdio_power_on(struct esp_sdio_ctrl *sctrl)
{
        int err = 0;

        if (sctrl->off == false)
                return err;

        sdio_claim_host(sctrl->func);
        err = sdio_enable_func(sctrl->func);

        if (err) {
                esp_dbg(ESP_DBG_ERROR, "Unable to enable sdio func: %d\n", err);
                sdio_release_host(sctrl->func);
                return err;
        }

        sdio_release_host(sctrl->func);

        /* ensure device is up */
        msleep(5);

        sctrl->off = false;

        return err;
}

static int esdio_power_off(struct esp_sdio_ctrl *sctrl)
{
        int err;

        if (sctrl->off)
                return 0;

        sdio_claim_host(sctrl->func);
        err = sdio_disable_func(sctrl->func);
        sdio_release_host(sctrl->func);

        if (err)
                return err;

        sctrl->off = true;

        return err;
}

void sif_enable_irq(struct esp_pub *epub) 
{
        int err;
        struct esp_sdio_ctrl *sctrl = NULL;

        sctrl = (struct esp_sdio_ctrl *)epub->sif;

        sdio_claim_host(sctrl->func);

        err = sdio_claim_irq(sctrl->func, sif_dsr);

        if (err)
                esp_dbg(ESP_DBG_ERROR, "sif %s failed\n", __func__);

        atomic_set(&epub->sip->state, SIP_BOOT);

        atomic_set(&sctrl->irq_installed, 1);

        sdio_release_host(sctrl->func);
}

void sif_disable_irq(struct esp_pub *epub) 
{
        int err;
        struct esp_sdio_ctrl *sctrl = (struct esp_sdio_ctrl *)epub->sif;
        int i = 0;
                
        if (atomic_read(&sctrl->irq_installed) == 0)
                return;
        
	    sdio_claim_host(sctrl->func);

        while (atomic_read(&sctrl->irq_handling)) {
                sdio_release_host(sctrl->func);
                schedule_timeout(HZ / 100);
                sdio_claim_host(sctrl->func);
                if (i++ >= 400) {
                        esp_dbg(ESP_DBG_ERROR, "%s force to stop irq\n", __func__);
                        break;
                }
        }

        err = sdio_release_irq(sctrl->func);

        if (err) {
                esp_dbg(ESP_DBG_ERROR, "%s release irq failed\n", __func__);
        }

        atomic_set(&sctrl->irq_installed, 0);

        sdio_release_host(sctrl->func);

}

void sif_set_clock(struct sdio_func *func, int clk)
{
	struct mmc_host *host = NULL;
	struct mmc_card *card = NULL;
	
	card = func->card;
	host = card->host;

	sdio_claim_host(func);

	//currently only set clock
	host->ios.clock = clk * 1000000;

	esp_dbg(ESP_SHOW, "%s clock is %u\n", __func__, host->ios.clock);
	if (host->ios.clock > host->f_max) {
		host->ios.clock = host->f_max;
	}
	host->ops->set_ios(host, &host->ios);

	mdelay(2);

	sdio_release_host(func);
}

static int esp_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
static void esp_sdio_remove(struct sdio_func *func);

static int esp_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) 
{
        int err = 0;
        struct esp_pub *epub;
        struct esp_sdio_ctrl *sctrl;

        esp_dbg(ESP_DBG_TRACE,
                        "sdio_func_num: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
                        func->num, func->vendor, func->device, func->max_blksize,
                        func->cur_blksize);
	if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){
		sctrl = kzalloc(sizeof(struct esp_sdio_ctrl), GFP_KERNEL);

		if (sctrl == NULL) {
			return -ENOMEM;
		}

		/* temp buffer reserved for un-dma-able request */
		sctrl->dma_buffer = kzalloc(ESP_DMA_IBUFSZ, GFP_KERNEL);

		if (sctrl->dma_buffer == NULL) {
                	err = -ENOMEM;
			goto _err_last;
		}
		sif_sctrl = sctrl;
        	sctrl->slc_blk_sz = SIF_SLC_BLOCK_SIZE;
        	
		epub = esp_pub_alloc_mac80211(&func->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
		if (sif_get_ate_config() == 0) {
			err = ext_gpio_init(epub);
			if (err) {
                		esp_dbg(ESP_DBG_ERROR, "ext_irq_work_init failed %d\n", err);
				goto _err_epub;
			}
		}
#endif

	} else {
		sctrl = sif_sctrl;
		sif_sctrl = NULL;
		epub = sctrl->epub;
		SET_IEEE80211_DEV(epub->hw, &func->dev);
		epub->dev = &func->dev;
	}

        epub->sdio_state = sif_sdio_state;

        sctrl->func = func;
        sdio_set_drvdata(func, sctrl);

        sctrl->id = id;
        sctrl->off = true;

        /* give us some time to enable, in ms */
        func->enable_timeout = 100;

        err = esdio_power_on(sctrl);
        esp_dbg(ESP_DBG_TRACE, " %s >> power_on err %d \n", __func__, err);

        if (err){
                if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT)
                	goto _err_ext_gpio;
		else
			goto _err_second_init;
        }
        check_target_id(epub);

        sdio_claim_host(func);

        err = sdio_set_block_size(func, sctrl->slc_blk_sz);

        if (err) {
                esp_dbg(ESP_DBG_ERROR, "Set sdio block size %d failed: %d)\n",
                                sctrl->slc_blk_sz, err);
                sdio_release_host(func);
                if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT)
                	goto _err_off;
		else
			goto _err_second_init;
        }

        sdio_release_host(func);

#ifdef LOWER_CLK 
        /* fix clock for dongle */
	sif_set_clock(func, 23);
#endif //LOWER_CLK

        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;
        }

        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_off:
        esdio_power_off(sctrl);
_err_ext_gpio:
#ifdef USE_EXT_GPIO
	if (sif_get_ate_config() == 0)
		ext_gpio_deinit();
_err_epub:
#endif
        esp_pub_dealloc_mac80211(epub);
_err_dma:
        kfree(sctrl->dma_buffer);
_err_last:
        kfree(sctrl);
_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_sdio_remove(func);
	return err;
}

static void esp_sdio_remove(struct sdio_func *func) 
{
        struct esp_sdio_ctrl *sctrl = NULL;

	esp_dbg(ESP_SHOW, "%s enter\n", __func__);

        sctrl = sdio_get_drvdata(func);

        if (sctrl == NULL) {
                esp_dbg(ESP_DBG_ERROR, "%s no sctrl\n", __func__);
                return;
        }

        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){
                	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	
			if (sif_get_ate_config() == 0)
				ext_gpio_deinit();
#endif
		} else {
			//sif_disable_target_interrupt(sctrl->epub);
			atomic_set(&sctrl->epub->sip->state, SIP_STOP);
			sif_disable_irq(sctrl->epub);
		}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0))
                esdio_power_off(sctrl);
                esp_dbg(ESP_DBG_TRACE, "%s power off \n", __func__);
#endif /* kernel < 3.3.0 */

#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);
		}

        } while (0);
        
	sdio_set_drvdata(func,NULL);
	
        esp_dbg(ESP_DBG_TRACE, "eagle sdio remove complete\n");
}

MODULE_DEVICE_TABLE(sdio, esp_sdio_devices);

static int esp_sdio_suspend(struct device *dev)
{
    //#define dev_to_sdio_func(d)     container_of(d, struct sdio_func, dev)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
    struct sdio_func *func = dev_to_sdio_func(dev);
#else
    struct sdio_func *func = container_of(dev, struct sdio_func, dev);
#endif
	struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
	struct esp_pub *epub = sctrl->epub;	

        printk("%s", __func__);
#if 0
	sip_send_suspend_config(epub, 1);
#endif
	atomic_set(&epub->ps.state, ESP_PM_ON);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34))
    do{
        u32 sdio_flags = 0;
        int ret = 0;
        sdio_flags = sdio_get_host_pm_caps(func);

        if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
            printk("%s can't keep power while host is suspended\n", __func__);
        }

        /* keep power while host suspended */
        ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
        if (ret) {
                printk("%s error while trying to keep power\n", __func__);
        }
    }while(0);
#endif


        return 0;

}

static int esp_sdio_resume(struct device *dev)
{
        esp_dbg(ESP_DBG_ERROR, "%s", __func__);

        return 0;
}

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
static const struct dev_pm_ops esp_sdio_pm_ops = {
        .suspend= esp_sdio_suspend,
        .resume= esp_sdio_resume,
};
#else
static struct pm_ops esp_sdio_pm_ops = {
        .suspend= esp_sdio_suspend,
        .resume= esp_sdio_resume,
};
#endif

static struct sdio_driver esp_sdio_driver = {
                .name = "eagle_sdio",
                .id_table = esp_sdio_devices,
                .probe = esp_sdio_probe,
                .remove = esp_sdio_remove,
                .drv = { .pm = &esp_sdio_pm_ops, },
};

static int esp_sdio_dummy_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
        esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);

        up(&esp_powerup_sem);
        
        return 0;
}

static void esp_sdio_dummy_remove(struct sdio_func *func) 
{
        return;
}

static struct sdio_driver esp_sdio_dummy_driver = {
                .name = "eagle_sdio_dummy",
                .id_table = esp_sdio_devices,
                .probe = esp_sdio_dummy_probe,
                .remove = esp_sdio_dummy_remove,
};

static int /*__init*/ esp_sdio_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 DRIVER_VER
        ver = DRIVER_VER;
        esp_dbg(ESP_SHOW, "\n***** EAGLE DRIVER VER:%llx*****\n\n", ver);
#endif
        edf_ret = esp_debugfs_init();

	request_init_conf();

        esp_wakelock_init();
        esp_wake_lock();

        do {
                sema_init(&esp_powerup_sem, 0);

                sif_platform_target_poweron();

                sif_platform_rescan_card(1);

                err = sdio_register_driver(&esp_sdio_dummy_driver);
                if (err) {
                        esp_dbg(ESP_DBG_ERROR, "eagle sdio 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();

                sdio_unregister_driver(&esp_sdio_dummy_driver);

                sif_platform_rescan_card(0);
                
                sif_platform_target_poweroff();
                
        } while (retry--);

        if (!powerup) {
                esp_dbg(ESP_DBG_ERROR, "eagle sdio can not power up!\n");

                err = -ENODEV;
                goto _fail;
        }

        esp_dbg(ESP_SHOW, "%s power up OK\n", __func__);

        sdio_unregister_driver(&esp_sdio_dummy_driver);
        
        sif_sdio_state = ESP_SDIO_STATE_FIRST_INIT;
	sema_init(&esp_powerup_sem, 0);

        sdio_register_driver(&esp_sdio_driver);

        if ((down_timeout(&esp_powerup_sem,
                                 msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) == 0 ) && sif_get_ate_config() == 0) {
		if(sif_sdio_state == ESP_SDIO_STATE_FIRST_NORMAL_EXIT){
                	sdio_unregister_driver(&esp_sdio_driver);

                	sif_platform_rescan_card(0);

			msleep(100);
                
			sif_platform_rescan_card(1);

			sif_sdio_state = ESP_SDIO_STATE_SECOND_INIT;
        	
			sdio_register_driver(&esp_sdio_driver);
		}
                
        }


        esp_register_early_suspend();
	esp_wake_unlock();
        return err;

_fail:
        esp_wake_unlock();
        esp_wakelock_destroy();

        return err;
}

static void  /*__exit*/ esp_sdio_exit(void) 
{
	esp_dbg(ESP_SHOW, "%s \n", __func__);

	esp_debugfs_exit();
	
        esp_unregister_early_suspend();

	sdio_unregister_driver(&esp_sdio_driver);
	
	sif_platform_rescan_card(0);

#ifndef FPGA_DEBUG
	sif_platform_target_poweroff();
#endif /* !FPGA_DEBUG */

        esp_wakelock_destroy();
}

MODULE_AUTHOR("Espressif System");
MODULE_DESCRIPTION("Driver for SDIO interconnected eagle low-power WLAN devices");
MODULE_LICENSE("GPL");
#endif /* ESP_USE_SDIO */
