mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
SDMMC:use gpio-interrupt to detect card.
Please attention to define the detect-pin name and the insert-card voltage in your board_xxxx.c.
This commit is contained in:
@@ -520,6 +520,10 @@ static void rkusb_wifi_power(int on) {
|
||||
|
||||
#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK2928_PIN0_PB2
|
||||
|
||||
#define RK29SDK_SD_CARD_DETECT_N RK2928_PIN2_PA7 //According to your own project to set the value of card-detect-pin.
|
||||
#define RK29SDK_SD_CARD_INSERT_LEVEL GPIO_LOW // set the voltage of insert-card. Please pay attention to the default setting.
|
||||
|
||||
|
||||
#endif //endif ---#ifdef CONFIG_SDMMC_RK29
|
||||
|
||||
#ifdef CONFIG_SDMMC0_RK29
|
||||
@@ -527,7 +531,13 @@ static int rk29_sdmmc0_cfg_gpio(void)
|
||||
{
|
||||
rk29_sdmmc_set_iomux(0, 0xFFFF);
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_GPIO1C1);
|
||||
// gpio_request(RK29SDK_SD_CARD_DETECT_N, "sd-detect");
|
||||
// gpio_direction_output(RK29SDK_SD_CARD_DETECT_N,GPIO_HIGH);//set mmc0-data1 to high.
|
||||
#else
|
||||
rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT)
|
||||
gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp");
|
||||
@@ -557,7 +567,14 @@ struct rk29_sdmmc_platform_data default_sdmmc0_data = {
|
||||
#else
|
||||
.use_dma = 0,
|
||||
#endif
|
||||
.detect_irq = RK2928_PIN1_PC1, // INVALID_GPIO
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
.detect_irq = RK29SDK_SD_CARD_DETECT_N,
|
||||
.insert_card_level = RK29SDK_SD_CARD_INSERT_LEVEL,
|
||||
#else
|
||||
.detect_irq = INVALID_GPIO,
|
||||
#endif
|
||||
|
||||
.enable_sd_wakeup = 0,
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT)
|
||||
|
||||
@@ -83,6 +83,45 @@ struct rk29fb_info {
|
||||
void (*set_screen_info)(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info );
|
||||
};
|
||||
|
||||
struct rksdmmc_iomux {
|
||||
char *name; //set the MACRO of gpio
|
||||
int fgpio;
|
||||
int fmux;
|
||||
};
|
||||
|
||||
struct rksdmmc_gpio {
|
||||
int io; //set the address of gpio
|
||||
char name[64]; //
|
||||
int enable; // disable = !enable //set the default value,i.e,GPIO_HIGH or GPIO_LOW
|
||||
struct rksdmmc_iomux iomux;
|
||||
};
|
||||
|
||||
|
||||
struct rksdmmc_gpio_board {
|
||||
struct rksdmmc_gpio clk_gpio;
|
||||
struct rksdmmc_gpio cmd_gpio;
|
||||
struct rksdmmc_gpio data0_gpio;
|
||||
struct rksdmmc_gpio data1_gpio;
|
||||
struct rksdmmc_gpio data2_gpio;
|
||||
struct rksdmmc_gpio data3_gpio;
|
||||
|
||||
struct rksdmmc_gpio detect_irq;
|
||||
struct rksdmmc_gpio power_en_gpio;
|
||||
struct rksdmmc_gpio write_prt;
|
||||
struct rksdmmc_gpio sdio_irq_gpio;
|
||||
};
|
||||
|
||||
|
||||
struct rksdmmc_gpio_wifi_moudle {
|
||||
struct rksdmmc_gpio power_n;
|
||||
struct rksdmmc_gpio reset_n;
|
||||
struct rksdmmc_gpio vddio;
|
||||
struct rksdmmc_gpio bgf_int_b;
|
||||
struct rksdmmc_gpio wifi_int_b;
|
||||
struct rksdmmc_gpio gps_sync;
|
||||
};
|
||||
|
||||
|
||||
struct rk29_sdmmc_platform_data {
|
||||
unsigned int host_caps;
|
||||
unsigned int host_ocr_avail;
|
||||
@@ -94,6 +133,7 @@ struct rk29_sdmmc_platform_data {
|
||||
int (*status)(struct device *);
|
||||
int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
|
||||
int detect_irq;
|
||||
int insert_card_level;
|
||||
int enable_sd_wakeup;
|
||||
int write_prt;
|
||||
unsigned int sdio_INT_gpio; //add gpio INT for sdio interrupt.Modifed by xbw at 2012-08-09
|
||||
|
||||
@@ -32,6 +32,16 @@ if SDMMC_RK29
|
||||
You will add the feature of write-protect for sdmmc-card if you say Yes.
|
||||
Please note that this feature requires hardware support.
|
||||
|
||||
config SDMMC0_RK29_SDCARD_DET_FROM_GPIO
|
||||
bool "use the gpio-interrupt to detect card"
|
||||
default n
|
||||
depends on SDMMC0_RK29
|
||||
help
|
||||
You can detect the presence of card by the gpio-interrupt if you say Yes.
|
||||
Of course, you must define the pin-name for the detect-pin.
|
||||
|
||||
If you say No, then detect the card by register interrupt.
|
||||
|
||||
# config USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD
|
||||
# depends on SDMMC0_RK29
|
||||
# bool "Switch the driver SDMMC0 for the debug of wifi_develop_board."
|
||||
|
||||
@@ -86,12 +86,22 @@ int debug_level = 5;
|
||||
|
||||
#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE )
|
||||
|
||||
#if SDMMC_USE_INT_UNBUSY
|
||||
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
|
||||
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
#if SDMMC_USE_INT_UNBUSY
|
||||
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS )
|
||||
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
|
||||
#else
|
||||
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS )
|
||||
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
|
||||
#endif
|
||||
#else
|
||||
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
|
||||
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
|
||||
#if SDMMC_USE_INT_UNBUSY
|
||||
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
|
||||
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
|
||||
#else
|
||||
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
|
||||
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define RK29_SDMMC_SEND_START_TIMEOUT 3000 //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
|
||||
@@ -99,7 +109,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.4.06 The last modify date is 2012-09-26"
|
||||
#define RK29_SDMMC_VERSION "Ver.4.07 The last modify date is 2012-09-27"
|
||||
|
||||
#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
|
||||
#define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC
|
||||
@@ -242,10 +252,10 @@ struct rk29_sdmmc {
|
||||
unsigned int complete_done;
|
||||
unsigned int retryfunc;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int gpio_irq;
|
||||
int gpio_det;
|
||||
#endif
|
||||
int insert_level;
|
||||
struct delayed_work work;
|
||||
|
||||
#ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO
|
||||
unsigned int sdio_INT_gpio;
|
||||
@@ -1564,16 +1574,23 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc)
|
||||
switch(host->pdev->id)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
#ifdef CONFIG_PM
|
||||
if(host->gpio_det == INVALID_GPIO)
|
||||
return 1;
|
||||
#endif
|
||||
{
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
if(host->gpio_det == INVALID_GPIO)
|
||||
return 1;
|
||||
|
||||
cdetect = gpio_get_value(host->gpio_det);
|
||||
if(host->insert_level)
|
||||
cdetect = cdetect?1:0;
|
||||
else
|
||||
cdetect = cdetect?0:1;
|
||||
|
||||
#else
|
||||
cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT);
|
||||
|
||||
cdetect = (cdetect & SDMMC_CARD_DETECT_N)?0:1;
|
||||
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3463,13 +3480,75 @@ static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id)
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
static irqreturn_t det_keys_isr(int irq, void *dev_id);
|
||||
static void rk29_sdmmc_detect_change_work(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
struct rk29_sdmmc *host = container_of(work, struct rk29_sdmmc, work.work);
|
||||
|
||||
rk28_send_wakeup_key();
|
||||
rk29_sdmmc_detect_change(host);
|
||||
|
||||
free_irq(host->gpio_irq, host);
|
||||
ret = request_irq(host->gpio_irq,det_keys_isr,
|
||||
rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING,
|
||||
"sd_detect",
|
||||
host);
|
||||
}
|
||||
#endif
|
||||
|
||||
static irqreturn_t det_keys_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rk29_sdmmc *host = dev_id;
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
bool present;
|
||||
bool present_old;
|
||||
|
||||
present = rk29_sdmmc_get_cd(host->mmc);
|
||||
present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
|
||||
|
||||
if(present != present_old)
|
||||
{
|
||||
printk(KERN_INFO "\n******************\n%s: present Old=%d ==> New=%d . [%s]\n",\
|
||||
__FUNCTION__, present_old, present, host->dma_name);
|
||||
|
||||
disable_irq_nosync(host->gpio_irq);
|
||||
|
||||
#if 1
|
||||
del_timer(&host->request_timer);
|
||||
del_timer(&host->DTO_timer);
|
||||
rk29_sdmmc_dealwith_timeout(host);
|
||||
#endif
|
||||
|
||||
if(present)
|
||||
{
|
||||
set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
|
||||
schedule_delayed_work(&host->work, msecs_to_jiffies(500));
|
||||
}
|
||||
else
|
||||
{
|
||||
clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
|
||||
host->mmc->re_initialized_flags = 0;
|
||||
schedule_delayed_work(&host->work, 0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n",
|
||||
gpio_get_value(RK29_SDMMC0DETECTN_GPIO)?"removed":"insert");
|
||||
rk29_sdmmc_detect_change((unsigned long)dev_id);
|
||||
#endif
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rk29_sdmmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_host *mmc;
|
||||
struct rk29_sdmmc *host;
|
||||
struct resource *regs;
|
||||
struct rk29_sdmmc_platform_data *pdata;
|
||||
//int irq;
|
||||
int level_value;
|
||||
int ret = 0;
|
||||
|
||||
#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)
|
||||
@@ -3514,10 +3593,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
|
||||
host->mrq = NULL;
|
||||
host->new_mrq = NULL;
|
||||
host->irq_state = true;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
host->gpio_det = pdata->detect_irq;
|
||||
host->insert_level = pdata->insert_card_level;
|
||||
#endif
|
||||
|
||||
host->set_iomux = pdata->set_iomux;
|
||||
|
||||
#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)
|
||||
@@ -3711,6 +3792,32 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
|
||||
goto err_dmaunmap;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
if(INVALID_GPIO != host->gpio_det)
|
||||
{
|
||||
INIT_DELAYED_WORK(&host->work, rk29_sdmmc_detect_change_work);
|
||||
ret = gpio_request(host->gpio_det, "sd_detect");
|
||||
if(ret < 0) {
|
||||
dev_err(&pdev->dev, "gpio_request error\n");
|
||||
goto err_dmaunmap;
|
||||
}
|
||||
gpio_direction_input(host->gpio_det);
|
||||
|
||||
level_value = gpio_get_value(host->gpio_det);
|
||||
printk("%d..%s: level value =%d ======trace detect =====\n",__LINE__ ,__FUNCTION__, level_value);
|
||||
|
||||
host->gpio_irq = gpio_to_irq(host->gpio_det);
|
||||
ret = request_irq(host->gpio_irq, det_keys_isr,
|
||||
level_value?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
|
||||
"sd_detect",
|
||||
host);
|
||||
if(ret < 0) {
|
||||
dev_err(&pdev->dev, "gpio request_irq error\n");
|
||||
goto err_dmaunmap;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)
|
||||
if(RK29_CTRL_SDIO1_ID == host->pdev->id)
|
||||
{
|
||||
@@ -3870,18 +3977,10 @@ static int __exit rk29_sdmmc_remove(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static irqreturn_t det_keys_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rk29_sdmmc *host = dev_id;
|
||||
dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n",
|
||||
gpio_get_value(RK29_SDMMC0DETECTN_GPIO)?"removed":"insert");
|
||||
rk29_sdmmc_detect_change((unsigned long)dev_id);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
|
||||
{
|
||||
int ret = 0;
|
||||
#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
|
||||
#if defined(CONFIG_ARCH_RK29)
|
||||
rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2);
|
||||
@@ -3895,6 +3994,7 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
|
||||
|
||||
gpio_request(RK29_SDMMC0DETECTN_GPIO, "sd_detect");
|
||||
gpio_direction_input(RK29_SDMMC0DETECTN_GPIO);
|
||||
|
||||
host->gpio_irq = gpio_to_irq(RK29_SDMMC0DETECTN_GPIO);
|
||||
ret = request_irq(host->gpio_irq, det_keys_isr,
|
||||
(gpio_get_value(RK29_SDMMC0DETECTN_GPIO))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
|
||||
@@ -3902,10 +4002,16 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
|
||||
host);
|
||||
|
||||
enable_irq_wake(host->gpio_irq);
|
||||
|
||||
#endif ////----end of #if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
|
||||
{
|
||||
#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
|
||||
disable_irq_wake(host->gpio_irq);
|
||||
free_irq(host->gpio_irq,host);
|
||||
gpio_free(RK29_SDMMC0DETECTN_GPIO);
|
||||
@@ -3919,6 +4025,8 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
|
||||
#elif defined(CONFIG_ARCH_RK2928)
|
||||
rk29_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN);
|
||||
#endif
|
||||
|
||||
#endif ////----end of #if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
}
|
||||
|
||||
static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
@@ -3936,8 +4044,10 @@ static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
ret = mmc_suspend_host(mmc, state);
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
if(rk29_sdmmc_sdcard_suspend(host) < 0)
|
||||
dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -3953,7 +4063,11 @@ static int rk29_sdmmc_resume(struct platform_device *pdev)
|
||||
{
|
||||
if (mmc)
|
||||
{
|
||||
|
||||
#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
|
||||
rk29_sdmmc_sdcard_resume(host);
|
||||
#endif
|
||||
|
||||
ret = mmc_resume_host(mmc);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user