diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/net/wireless/eagle/sdio_sif_esp.c | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/net/wireless/eagle/sdio_sif_esp.c')
-rwxr-xr-x | drivers/net/wireless/eagle/sdio_sif_esp.c | 944 |
1 files changed, 944 insertions, 0 deletions
diff --git a/drivers/net/wireless/eagle/sdio_sif_esp.c b/drivers/net/wireless/eagle/sdio_sif_esp.c new file mode 100755 index 00000000..3ba1edae --- /dev/null +++ b/drivers/net/wireless/eagle/sdio_sif_esp.c @@ -0,0 +1,944 @@ +/* + * Copyright (c) 2010 -2013 Espressif System. + * + * sdio serial i/f driver + * - sdio device control routines + * - sync/async DMA/PIO read/write + * + */ +#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" +#ifdef ANDROID +#include "esp_android.h" +#endif /* ANDROID */ +#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 +extern void set_wifi_name(char * name); + +//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); + +struct sif_req * sif_alloc_req(struct esp_sdio_ctrl *sctrl); + +#include "sdio_stub.c" + +void sif_lock_bus(struct esp_pub *epub) +{ + EPUB_FUNC_CHECK(epub); + + sdio_claim_host(EPUB_TO_FUNC(epub)); +} + +void sif_unlock_bus(struct esp_pub *epub) +{ + EPUB_FUNC_CHECK(epub); + + sdio_release_host(EPUB_TO_FUNC(epub)); +} + +#ifdef SDIO_TEST +static void sif_test_tx(struct esp_sdio_ctrl *sctrl) +{ + int i, err = 0; + + for (i = 0; i < 500; i++) { + sctrl->dma_buffer[i] = i; + } + + sdio_claim_host(sctrl->func); + err = sdio_memcpy_toio(sctrl->func, 0x10001 - 500, sctrl->dma_buffer, 500); + sif_platform_check_r1_ready(sctrl->epub); + sdio_release_host(sctrl->func); + + esp_dbg(ESP_DBG, "%s toio err %d\n", __func__, err); +} + +static void sif_test_dsr(struct sdio_func *func) +{ + struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func); + + sdio_release_host(sctrl->func); + + /* no need to read out registers in normal operation any more */ + //sif_io_sync(sctrl->epub, SIF_SLC_WINDOW_END_ADDR - 64, sctrl->dma_buffer, 64, SIF_FROM_DEVICE | SIF_INC_ADDR | SIF_SYNC | SIF_BYTE_BASIS); + // + esp_dsr(sctrl->epub); + + sdio_claim_host(func); + + //show_buf(sctrl->dma_buffer, 64); +} + +void sif_test_rx(struct esp_sdio_ctrl *sctrl) +{ + int err = 0; + + sdio_claim_host(sctrl->func); + + err = sdio_claim_irq(sctrl->func, sif_test_dsr); + + if (err) + esp_dbg(ESP_DBG_ERROR, "sif %s failed\n", __func__); + + sdio_release_host(sctrl->func); +} +#endif //SDIO_TEST + +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; + + ASSERT(epub != NULL); + ASSERT(buf != NULL); + + sctrl = (struct esp_sdio_ctrl *)epub->sif; + func = sctrl->func; + ASSERT(func != NULL); + + 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); + } + + 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; + + ASSERT(epub != NULL); + ASSERT(buf != NULL); + + sctrl = (struct esp_sdio_ctrl *)epub->sif; + func = sctrl->func; + ASSERT(func != NULL); + + 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); + } + + return err; +} + +int sif_lldesc_read_sync(struct esp_pub *epub, u8 *buf, u32 len) +{ + struct esp_sdio_ctrl *sctrl = NULL; + u32 read_len; + + ASSERT(epub != NULL); + ASSERT(buf != NULL); + + 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; + + ASSERT(epub != NULL); + ASSERT(buf != NULL); + + 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; + + ASSERT(epub != NULL); + ASSERT(buf != NULL); + + 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; + + ASSERT(epub != NULL); + ASSERT(buf != NULL); + + 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; + + assert(sctrl != NULL); + + 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); + set_wifi_name("eagle.ko"); /* add by VIA */ + if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){ + sctrl = kzalloc(sizeof(struct esp_sdio_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(&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 + 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, &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_epub; + 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); + goto _err_off; + } + + sdio_release_host(func); + +#ifdef SDIO_TEST + sif_test_tx(sctrl); +#else + +#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; + } + +#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_off: + esdio_power_off(sctrl); +_err_epub: + 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; + + 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){ + do{ + int err; + sif_lock_bus(sctrl->epub); + sif_raw_dummy_read(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); + } + +#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 3000 + int err; + u64 ver; + int retry = 0;//mod from 3 to 0 to reduce detect time. + 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*****%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(); + + 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) + { + if(sif_sdio_state == ESP_SDIO_STATE_FIRST_NORMAL_EXIT){ + sdio_unregister_driver(&esp_sdio_driver); + + sif_platform_rescan_card(0); + + msleep(80); + + 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_DBG_TRACE, "%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 */ |