From eb1ab60e9f7308d90aff40998178ff2a8a502a29 Mon Sep 17 00:00:00 2001 From: xbw Date: Mon, 20 May 2013 10:59:14 +0800 Subject: [PATCH] 1. The accuracy enhanced gpio_detect_card, such as RK2926. 2. To enhance removeal-insert card, voltage stability. 3. add the suspend-resume process for SDIO module. 4. 4. close the clock when the sdio go into suspend. refer to No3. 5. 5. add the wake-up-host for wifi when use CONFIG_RK29_SDIO_IRQ_FROM_GPIO. --- arch/arm/plat-rk/include/plat/board.h | 4 +- arch/arm/plat-rk/rk-sdmmc-ops.c | 4 +- drivers/mmc/core/sdio.c | 7 ++ drivers/mmc/host/rk29_sdmmc.c | 109 +++++++++++++++++++++++--- 4 files changed, 108 insertions(+), 16 deletions(-) diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index 4529b1ea789a..43ee181cd184 100755 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -168,7 +168,9 @@ struct rk29_sdmmc_platform_data { int enable_sd_wakeup; int write_prt; int write_prt_enalbe_level; - unsigned int sdio_INT_gpio; + unsigned int sdio_INT_gpio; + int sdio_INT_level; +#define USE_SDIO_INT_LEVEL /*In order to be compatible with old project, those who do not define the member sdio_INT_level */ struct rksdmmc_gpio det_pin_info; int (*sd_vcc_reset)(void); }; diff --git a/arch/arm/plat-rk/rk-sdmmc-ops.c b/arch/arm/plat-rk/rk-sdmmc-ops.c index 784b7585c994..2d66bc459f17 100644 --- a/arch/arm/plat-rk/rk-sdmmc-ops.c +++ b/arch/arm/plat-rk/rk-sdmmc-ops.c @@ -624,9 +624,9 @@ static struct rksdmmc_gpio_board rksdmmc1_gpio_init = { * define the varaious operations for SDMMC module * Generally only the author of SDMMC module will modify this section. *************************************************************************/ - #if !defined(CONFIG_SDMMC_RK29_OLD) -static void rk29_sdmmc_gpio_open(int device_id, int on) +//static void rk29_sdmmc_gpio_open(int device_id, int on) +void rk29_sdmmc_gpio_open(int device_id, int on) { switch(device_id) { diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index e1bf6274cf0c..41f400cb5e57 100755 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -689,8 +689,15 @@ static int mmc_sdio_resume(struct mmc_host *host) } } +#if defined(CONFIG_MTK_COMBO) && defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2) + /* sdio_funcs are NOT resumed yet! Signal irq only in host driver. */ + // + // do not to wake up sdio_irq_thread; noted by xbw at 2013-05-08 + // +#else if (!err && host->sdio_irqs) wake_up_process(host->sdio_irq_thread); +#endif mmc_release_host(host); /* diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index a2d2149af78c..6f9280097345 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -70,6 +70,17 @@ int debug_level = 5; #define SDMMC_USE_INT_UNBUSY 0///1 #endif +/* +** You can set the macro to true, if some module wants to use this feature, which is about SDIO suspend-resume. +** As the following example. +** added by xbw at 2013-05-08 +*/ +#if defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2) +#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME 1 +#else +#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME 0 +#endif + #define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE ) #if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) @@ -95,7 +106,7 @@ int debug_level = 5; #define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT #define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react. -#define RK29_SDMMC_VERSION "Ver.5.03 The last modify date is 2013-02-21" +#define RK29_SDMMC_VERSION "Ver.5.05 The last modify date is 2013-05-08" #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) #define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC @@ -253,6 +264,7 @@ struct rk29_sdmmc { #ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO unsigned int sdio_INT_gpio; unsigned int sdio_irq; + unsigned long trigger_level; #endif #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) @@ -1484,6 +1496,9 @@ static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *dat if (sg->offset & 3 || sg->length & 3) { data->error = -EILSEQ; + printk("%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d [%s]\n", \ + __FUNCTION__, __LINE__, host->cmd->opcode,\ + host->cmd->arg,data->blksz, data->blocks, host->dma_name); return ; } } @@ -1564,7 +1579,9 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc) { struct rk29_sdmmc *host = mmc_priv(mmc); u32 cdetect=1; - +#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) + int i=0,cdetect1=0, cdetect2=0; +#endif switch(host->pdev->id) { case 0: @@ -1573,7 +1590,16 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc) if(host->det_pin.io == INVALID_GPIO) return 1; - cdetect = gpio_get_value(host->det_pin.io); + for(i=0;i<5;i++) + { + udelay(10); + cdetect1 = gpio_get_value(host->det_pin.io); + udelay(10); + cdetect2 = gpio_get_value(host->det_pin.io); + if(cdetect1 == cdetect2) + break; + } + cdetect = cdetect2; if(host->det_pin.enable) cdetect = cdetect?1:0; else @@ -2377,7 +2403,7 @@ static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } - +extern void rk29_sdmmc_gpio_open(int device_id, int on); static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { int timeout = 250; @@ -2425,8 +2451,11 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) rk29_sdmmc_reset_controller(host); } - //power-off - gpio_direction_output(host->gpio_power_en, !(host->gpio_power_en_level)); + + rk29_sdmmc_gpio_open(0, 0); + //power-off + gpio_direction_output(host->gpio_power_en, !(host->gpio_power_en_level)); + goto out; } break; @@ -2463,7 +2492,8 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } - if(!(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDIO1_ID != host->pdev->id))) + if((!(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags))|| !rk29_sdmmc_get_cd(host->mmc)) + &&(RK29_CTRL_SDIO1_ID != host->pdev->id)) goto out; //exit the set_ios directly if the SDIO is not present. if(host->ctype != ios->bus_width) @@ -2564,11 +2594,22 @@ static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) struct rk29_sdmmc *host = mmc_priv(mmc); #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - if(enable) + if(enable) + { enable_irq(host->sdio_irq); - //enable_irq_wake(host->sdio_irq); - else + + #if !defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2) + enable_irq_wake(host->sdio_irq); + #endif + } + else + { disable_irq_nosync(host->sdio_irq); + + #if !defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2) + disable_irq_wake(host->sdio_irq); + #endif + } #else spin_lock_irqsave(&host->lock, flags); @@ -3441,6 +3482,11 @@ static void rk29_sdmmc1_check_status(unsigned long data) { if (status) { + #if RK_SDMMC_USE_SDIO_SUSPEND_RESUME + if(host->pdev->id == RK29_CTRL_SDIO1_ID) + host->mmc->pm_caps |= (MMC_PM_KEEP_POWER|MMC_PM_WAKE_SDIO_IRQ); + #endif + rk29_sdmmc_hw_init(host); set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200)); @@ -3594,6 +3640,9 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) if(RK29_CTRL_SDIO1_ID == host->pdev->id) { host->sdio_INT_gpio = pdata->sdio_INT_gpio; + #ifdef USE_SDIO_INT_LEVEL + host->trigger_level = pdata->sdio_INT_level; + #endif } #endif @@ -3826,7 +3875,11 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) gpio_pull_updown(host->sdio_INT_gpio, 0); //disable default internal pull-down host->sdio_irq = gpio_to_irq(host->sdio_INT_gpio); + #ifdef USE_SDIO_INT_LEVEL + trigger_flags = (host->trigger_level==GPIO_HIGH)?IRQF_TRIGGER_HIGH:IRQF_TRIGGER_LOW; + #else trigger_flags = IRQF_TRIGGER_LOW; + #endif //printk("%d..%s sdio interrupt gpio level=%lu ====[%s]====\n", __LINE__, __FUNCTION__, trigger_flags, host->dma_name); ret = request_irq(host->sdio_irq, rk29_sdmmc_sdio_irq_cb, trigger_flags, @@ -3839,8 +3892,10 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) __FUNCTION__, __LINE__, ret, host->dma_name); host->errorstep = 0x8D; goto err_dmaunmap; - } - disable_irq_nosync(host->sdio_irq); + } + + disable_irq_nosync(host->sdio_irq); + enable_irq_wake(host->sdio_irq); } #endif @@ -4034,6 +4089,22 @@ static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n"); #endif } +#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME + else if(host && host->pdev && (RK29_CTRL_SDIO1_ID == host->pdev->id)) + { + if (mmc) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + ret = mmc_suspend_host(mmc); +#else + ret = mmc_suspend_host(mmc, state); +#endif + if(!ret) + { + clk_disable(host->clk); + clk_disable(clk_get(&pdev->dev, "hclk_mmc")); + } + } +#endif // --#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME return ret; } @@ -4055,7 +4126,19 @@ static int rk29_sdmmc_resume(struct platform_device *pdev) ret = mmc_resume_host(mmc); } - } + } +#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME + else if(host && host->pdev && (RK29_CTRL_SDIO1_ID == host->pdev->id)) + { + if (mmc) + { + clk_enable(host->clk); + clk_enable(clk_get(&pdev->dev, "hclk_mmc")); + mdelay(20); + ret = mmc_resume_host(mmc); + } + } +#endif // --#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME return ret; } -- 2.34.1