新路程------imx6 sd卡部分摘要

首先iomux-mx6q.h里
mx6_sabresd_board_init里
if (cpu_is_mx6q()) {
mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads,
ARRAY_SIZE(mx6q_sabresd_pads));
这是gpio的初始化,MX6Q_PAD_GPIO_4__GPIO_1_4被初始化
在MX6Q_PAD_GPIO_4__GPIO_1_4里MX6Q_PAD_GPIO_4__GPIO_1_4
#define  MX6Q_PAD_GPIO_4__GPIO_1_4 \
(_MX6Q_PAD_GPIO_4__GPIO_1_4 | MUX_PAD_CTRL(NO_PAD_CTRL))

#define _MX6Q_PAD_GPIO_4__GPIO_1_4\

IOMUX_PAD(0x0608, 0x0238, 5, 0x0000, 0, 0),这个pin原来是用在按键上的,

也就是也是个中断pin,应该被人获取了,但是后续的sd卡里的中断注册却成功了。

所以查到driver/input/keyboard/gpio_keys.c里回去注册驱动,所以把这个c给注释了不让编译
看开发板原来的资源是linux下的
static const struct esdhc_platform_data mx6q_sabresd_sd2_data __initconst = {
.cd_gpio = SABRESD_SD2_CD,
//.wp_gpio = SABRESD_SD2_WP,
.keep_power_at_suspend = 1,
.support_8bit = 1,
.delay_line = 0,
.cd_type = ESDHC_CD_CONTROLLER,
};
然后看sd卡的资源,在board-mx6q_sabresd.c 里
static const struct esdhc_platform_data mx6q_sabresd_sd2_data __initconst = {
.cd_gpio = SABRESD_SD2_CD,
// .wp_gpio = SABRESD_SD2_WP,
.keep_power_at_suspend = 1,
.support_8bit = 1,
.delay_line = 0,
.cd_type = ESDHC_CD_CONTROLLER,
.runtime_pm = 1,
};
这个cd_gpio
//#define SABRESD_SD2_CD IMX_GPIO_NR(2, 2)
#define SABRESD_SD2_CD IMX_GPIO_NR(1, 4)  本来是2,2,现在用的1,4,其实这样改了以后本来是gpio2,2.现在gpio1,4,都是gpio功能,所以是一样的


在sdhci-esdhc-imx.c里
err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");


err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,mmc_hostname(host->mmc), host);
printk("matt-err2=%d \n",err);


Sdhci-esdhc-imx.c


tasklet_schedule(&sdhost->card_tasklet);
这个card_tasklet在下面init
sdhci.c
tasklet_init(&host->card_tasklet,
sdhci_tasklet_card, (unsigned long)host);

sdhci.c中
static void sdhci_tasklet_card(unsigned long param)
mmc_detect_change(host->mmc, msecs_to_jiffies(500));
core.c中
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
    printk("matt-mmc_detect_change\n");
wake_lock(&host->detect_wake_lock);
mmc_schedule_delayed_work(&host->detect, delay);  这里让host->detect对应的函数线程开始工作
}


这个函数线程init在
host.c中mmc_alloc_host函数中
INIT_DELAYED_WORK(&host->detect, mmc_rescan);


看看mmc_rescan
在core.c
void mmc_rescan(struct work_struct *work)
{
if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
   && !(host->caps & MMC_CAP_NONREMOVABLE))
host->bus_ops->detect(host);
这是一条路,是remove的时候用的而不是插入用的
这个detect
在sd.c
static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_sd_power_restore,
};


/*
 * Card detection callback from host.
 */
static void mmc_sd_detect(struct mmc_host *host)
{
int err = 0;
#ifdef CONFIG_MMC_PARANOID_SD_INIT
        int retries = 5;
#endif


BUG_ON(!host);
BUG_ON(!host->card);


mmc_claim_host(host);


/*
* Just check if our card has been removed.
*/
#ifdef CONFIG_MMC_PARANOID_SD_INIT
while(retries) {
err = mmc_send_status(host->card, NULL);
if (err) {
retries--;
udelay(5);
continue;
}
break;
}
if (!retries) {
printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
      __func__, mmc_hostname(host), err);
}
#else
err = mmc_send_status(host->card, NULL);
#endif
mmc_release_host(host);


if (err) {
mmc_sd_remove(host);


mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
}
}




core.c中
这是第二条路,是正确的路,被log验证了,是插入的时候用的
void mmc_rescan(struct work_struct *work)
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
extend_wakelock = true;
break;
}

static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
if (!mmc_attach_sdio(host))
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;

sd.c里
int mmc_attach_sd(struct mmc_host *host)
mmc_release_host(host);
err = mmc_add_card(host->card);
mmc_claim_host(host);

bus.c里
int mmc_add_card(struct mmc_card *card)
printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",


这里有中断了,但是由于电平是相反的,所以看看remove啥时候开始被调用
core.c中调用了后面的remove,由于ops一直没有绑定成功,所以这里一直失败,一开始我们的sd卡没有插入,
所以初始化到mmc_rescan_try_freq里的if (!mmc_attach_sd(host))里头没有绑定ops和host,所以当我们开机后插入sd卡,一样是进不了detect的,
还是跑初始化的mmc_rescan_try_freq里的if (!mmc_attach_sd(host))


if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
   && !(host->caps & MMC_CAP_NONREMOVABLE))
host->bus_ops->detect(host);这里如果detect失败就会调用下面的remove
这里的host->bus_ops在sd.c中

这里的host->caps在
Sdhci-esdhc-imx.c (drivers\mmc\host): host->mmc->caps |= MMC_CAP_NONREMOVABLE;
Sdhci-esdhc-imx.c (drivers\mmc\host): host->mmc->caps &= ~MMC_CAP_NONREMOVABLE;赋值的
而决定这个赋值的是
board-mx6q_sabresd.c
static const struct esdhc_platform_data mx6q_sabresd_sd2_data __initconst = {
.cd_gpio = SABRESD_SD2_CD,
// .wp_gpio = SABRESD_SD2_WP,
.keep_power_at_suspend = 1,
.support_8bit = 1,
.delay_line = 0,
.cd_type = ESDHC_CD_CONTROLLER,
.runtime_pm = 1,
};
而检测函数失败最后调用的就是下面的
sd.c
static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_sd_power_restore,
};


static void mmc_sd_remove(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(!host->card);


mmc_remove_card(host->card);
host->card = NULL;
}


获取gpio 1-4的状态可以
gpio_state = gpio_get_value(4);
    printk("matt-gpio_state=%d\n",gpio_state);

sd卡软件部分验证完毕,无事可做了,然而峰回路转,偶然把

static const struct esdhc_platform_data mx6q_sabresd_sd2_data __initconst = {
//.cd_gpio = SABRESD_SD2_CD,  把这个一注释,开机启动可以检测到了,但是热插拔还是有问题
// .wp_gpio = SABRESD_SD2_WP,
.keep_power_at_suspend = 1,
.support_8bit = 1,
.delay_line = 0,
.cd_type = ESDHC_CD_CONTROLLER,
.runtime_pm = 1,
};
我就纳闷了,一个管脚有什么影响,于是搜

在sdhci-esdhc-imx.c里看到

如果有cd pin,则这两句话会执行

imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;经过验证,这句话起主要作用

在sdhci.c中发现这个变量会影响sd卡的状态

if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
present = true;
else
present = sdhci_readl(host, SDHCI_PRESENT_STATE) &SDHCI_CARD_PRESENT;

由于前面设置的是取反,纳闷这里肯定走else,这个readl被我偶然看到在

sdhci.h中

static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
{
if (unlikely(host->ops->read_l))
return host->ops->read_l(host, reg);  这里的read_l就是sdhci-esdhc-imx.c里的.read_l = esdhc_readl_le,
else
return readl(host->ioaddr + reg);
}

然后到sdhci-esdhc-imx.c里

在esdhc_readl_le这个函数中

if (boarddata && gpio_is_valid(boarddata->cd_gpio)
&& g
pio_get_value(boarddata->cd_gpio))  //果然根据cd pin的状态决定当前卡的状态,由于我们的板子和开发板是相反的电平,所以一直出错
/* no card, if a valid gpio says so */
//val &= ~SDHCI_CARD_PRESENT;
val |= SDHCI_CARD_PRESENT;
else
/* in all other cases assume card is present */
//val |= SDHCI_CARD_PRESENT;
val &= ~SDHCI_CARD_PRESENT;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值