先感谢下
在测试移远的内核时发现居然无法在开机后自动识别SD卡。我这就纳闷了,于是去找原因。
1.了解SD卡的读写、容量、速度、电压等特性
口读写特性:根据读写特性可以将SD卡分为2种,一种是读写卡,生产出来就是空白卡。另一种是只读卡,生产出来就定制了内容。
口支持电压 :根据支持的电压可以将SD卡分为高电压SD卡和双重电压SD卡
口卡容量:这个分类就算了不影响我们的问题分析
口速度:根据速度可以将SD卡分为4类。类0:这种卡兼容所有速度;类2:其速度大于等于2MB/S;类4:其速度大于等于4MB/S;类6:其速度大于等于6MB/S;高容量SD卡支持速度类描述,其性能相当于或超过类2.
2.SD卡功能描述
主机与卡之间通信都是由主机控制的,主机发送的命令有两种,分别为广播命令和地址命令。
口广播命令:该命令是发给所有的卡,有些广播命令需要响应。
口地址命令:这些命令发往具体地址的卡,并且从这些卡生产响应。
SD卡有两种模式
口卡识别模式:主机被复位或者在总线上寻找新卡时,主机处于该状态下。卡在复位以后和收到SEND_RCA命令以前都处于此模式下。
口数据传输模式:卡在它们的RCA(发布卡的地址)第一次发布后进入数据传输模式。主机识别总线上所有的卡后进入数据传输模式。
卡状态 | 操作模式 |
无活动状态 | 无活动 |
空状态 | 卡识别模式 |
准备态 | |
识别态 | |
等待态 | 数据传输模式 |
传输态 | |
发送数据态 | |
接收数据态 | |
编程态 | |
断开态 |
1.操作状态的验证
通过一系列过程后,主机才能识别卡。
口在主机和卡通信前,主机不知道卡支持的电压,卡也不知道是否支持主机当前提供的电压。主机将发布一个复位命令(CMD0),带着它能提供给卡的电压信息。
口为了验证SD卡的接口操作状态,主机发送SEND_IF_COND(CMD8),SD卡通过分析SEND_IF_COND命令参数检测操作状态的有效性,主机通过检测SD分析后的响应来判断电压的有效性。
口如果SD能够在提供的电压下操作,则发回的响应带上提供的电压,且检测模式被设置在命令参数中。如果SD卡不支持主机提供的电压,则不响应且保存在空闲态下。在发现ACMD41命令初始化高容量SD卡前,强制发送CMD8命令。
口强制低电压主机在发送CMD8前发送ACMD41。万一双重电压SD卡没有收到CMD8命令且工作在高压状态,在这种情况下,低电压主机不发送CMD8命令给卡,则收到ACMD41后进入无活动状态。
口SD_SEND_OP_COND(ACMD41)命令是为SD卡主机识别卡或电压不匹配时拒绝卡的机制而设计的。主机发送命令操作数代表代表要求的电压窗口大小。如果SD卡在所给的范围内不能实现数据传输,将放弃下一步的总线操作而进入无活动状态。操作状态寄存器也将被定义。
口主机发出复位命令(CMD0)后,主机将发送CMD8确认电压的有效性再发送ACMD41命令重新初始化SD卡。
卡识别模式的状态可以用下面的状态图表示
卡总线被激活后,主机就开始卡的初始化和识别处理。初始化处理从设置它的操作状态和设置OCR中的HCS比特位命令SD_SEND_OP_COND(ACMD41)开始。HCS比特位被设置为1表示主机支持高容量SD卡。HCS被设置为0表示主机不支持高容易SD卡。
卡的初始化和识别更详细的流程
卡的识别模式结束后,主机时钟fpp(数据传输时钟速率)将保持为Fod(卡识别模式下的时钟),因为有些卡对操作时钟有限制。主机必须发生SEND_CSD(CMD9)来获得卡规格数据寄存器内容,如块大小、卡容量。广播命令SET_DSR(CMD4)配置所有识别卡的驱动阶段。它对DSR寄存器进行编程以适应应用总线布局、总线上的卡数目和数据传输频率。
SD卡数据传输模式下的状态图
linux的SD卡驱动程序在driver/mmc目录下,该目录包含card,core,host
host驱动部分:host的驱动部分是针对不同类型主机的驱动
core驱动部分:core驱动部分完成不同协议和规范的实现,如SD卡相关的状态或修改状态、修改寄存器等操作。
card驱动部分:SD卡属于块设备,card驱动部分为了将SD卡驱动成块设备。
有三种检测SD卡的方式:
1.在开机的时候通过CMD发送命令检测TF卡是否存在,这种方式不支持热插拔。
2.通过T卡座来检测,信号DETECTION连接在中断控制器上。在没有插卡的时候,DETECTION的引脚为低电平,插入卡后,DETECTION引脚为高电平,从而产生一个中断,即实现热插拔。由低到高还是由高到低是硬件和软件共同协调的。
3.通过CD/DAT3信号来检测,CD/DAT3连接在中断控制器上,并通过470K电阻下拉,在没有T卡插入时,该信号为低电平,一但有卡插入,卡内部的50k上拉电阻会把DATA3拉高至高电平,随机产生一个中断,实现了热插拔。
我选的是8GTF卡,我开发板支持的电呀2.7V-3.3V。因为开机上电能检测所以,现在的驱动是属于在开机的时候通过CMD发送命令检测TF卡是否存在。那会不会驱动没写好?所以取查找驱动,先去host下看看,因为其它两个很少会因芯片改动而改动的。移远这个模块使用的是高通的mdm9607,所以我们去找host下的msm_sdcc.c下的msmsdcc_probe函数。
static int
msmsdcc_probe(struct platform_device *pdev)
{
struct msm_mmc_platform_data *plat = pdev->dev.platform_data;
struct msmsdcc_host *host;
struct mmc_host *mmc;
struct resource *cmd_irqres = NULL;
struct resource *stat_irqres = NULL;
struct resource *memres = NULL;
struct resource *dmares = NULL;
int ret;
/* must have platform data */
if (!plat) {
pr_err("%s: Platform data not available\n", __func__);
ret = -EINVAL;
goto out;
}
if (pdev->id < 1 || pdev->id > 4)
return -EINVAL;
if (pdev->resource == NULL || pdev->num_resources < 2) {
pr_err("%s: Invalid resource\n", __func__);
return -ENXIO;
}
memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"cmd_irq");
stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"status_irq");
if (!cmd_irqres || !memres) {
pr_err("%s: Invalid resource\n", __func__);
return -ENXIO;
}
/*
* Setup our host structure
*/
mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
goto out;
}
host = mmc_priv(mmc);
host->pdev_id = pdev->id;
host->plat = plat;
host->mmc = mmc;
host->curr.cmd = NULL;
init_timer(&host->busclk_timer);
host->busclk_timer.data = (unsigned long) host;
host->busclk_timer.function = msmsdcc_busclk_expired;
host->cmdpoll = 1;
host->base = ioremap(memres->start, PAGE_SIZE);
if (!host->base) {
ret = -ENOMEM;
goto host_free;
}
host->cmd_irqres = cmd_irqres;
host->memres = memres;
host->dmares = dmares;
spin_lock_init(&host->lock);
tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
(unsigned long)host);
/*
* Setup DMA
*/
if (host->dmares) {
ret = msmsdcc_init_dma(host);
if (ret)
goto ioremap_free;
} else {
host->dma.channel = -1;
}
/* Get our clocks */
host->pclk = clk_get(&pdev->dev, "sdc_pclk");
if (IS_ERR(host->pclk)) {
ret = PTR_ERR(host->pclk);
goto dma_free;
}
host->clk = clk_get(&pdev->dev, "sdc_clk");
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
goto pclk_put;
}
ret = clk_set_rate(host->clk, msmsdcc_fmin);
if (ret) {
pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
goto clk_put;
}
ret = clk_prepare(host->pclk);
if (ret)
goto clk_put;
ret = clk_prepare(host->clk);
if (ret)
goto clk_unprepare_p;
/* Enable clocks */
ret = msmsdcc_enable_clocks(host);
if (ret)
goto clk_unprepare;
host->pclk_rate = clk_get_rate(host->pclk);
host->clk_rate = clk_get_rate(host->clk);
/*
* Setup MMC host structure
*/
mmc->ops = &msmsdcc_ops;
mmc->f_min = msmsdcc_fmin;
mmc->f_max = msmsdcc_fmax;
mmc->ocr_avail = plat->ocr_mask;
if (msmsdcc_4bit)
mmc->caps |= MMC_CAP_4_BIT_DATA;
if (msmsdcc_sdioirq)
mmc->caps |= MMC_CAP_SDIO_IRQ;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
mmc->max_segs = NR_SG;
mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
mmc->max_blk_count = 65536;
mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
mmc->max_seg_size = mmc->max_req_size;
msmsdcc_writel(host, 0, MMCIMASK0);
msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
host->saved_irq0mask = MCI_IRQENABLE;
/*
* Setup card detect change
*/
memset(&host->timer, 0, sizeof(host->timer));
if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) {
unsigned long irqflags = IRQF_SHARED |
(stat_irqres->flags & IRQF_TRIGGER_MASK);
host->stat_irq = stat_irqres->start;
ret = request_irq(host->stat_irq,
msmsdcc_platform_status_irq,
irqflags,
DRIVER_NAME " (slot)",
host);
if (ret) {
pr_err("%s: Unable to get slot IRQ %d (%d)\n",
mmc_hostname(mmc), host->stat_irq, ret);
goto clk_disable;
}
} else if (plat->register_status_notify) {
plat->register_status_notify(msmsdcc_status_notify_cb, host);
} else if (!plat->status)
pr_err("%s: No card detect facilities available\n",
mmc_hostname(mmc));
else {
init_timer(&host->timer);
host->timer.data = (unsigned long)host;
host->timer.function = msmsdcc_check_status;
host->timer.expires = jiffies + HZ;
add_timer(&host->timer);
}
if (plat->status) {
host->oldstat = host->plat->status(mmc_dev(host->mmc));
host->eject = !host->oldstat;
}
ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
DRIVER_NAME " (cmd)", host);
if (ret)
goto stat_irq_free;
ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
DRIVER_NAME " (pio)", host);
if (ret)
goto cmd_irq_free;
mmc_set_drvdata(pdev, mmc);
mmc_add_host(mmc);
pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
mmc_hostname(mmc), (unsigned long long)memres->start,
(unsigned int) cmd_irqres->start,
(unsigned int) host->stat_irq, host->dma.channel);
pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
(mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate);
pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject);
pr_info("%s: Power save feature enable = %d\n",
mmc_hostname(mmc), msmsdcc_pwrsave);
if (host->dma.channel != -1) {
pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
mmc_hostname(mmc), host->dma.cmd_busaddr,
host->dma.cmdptr_busaddr);
} else
pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
if (host->timer.function)
pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
return 0;
cmd_irq_free:
free_irq(cmd_irqres->start, host);
stat_irq_free:
if (host->stat_irq)
free_irq(host->stat_irq, host);
clk_disable:
msmsdcc_disable_clocks(host, 0);
clk_unprepare:
clk_unprepare(host->clk);
clk_unprepare_p:
clk_unprepare(host->pclk);
clk_put:
clk_put(host->clk);
pclk_put:
clk_put(host->pclk);
dma_free:
if (host->dmares)
dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata),
host->dma.nc, host->dma.nc_busaddr);
ioremap_free:
tasklet_kill(&host->dma_tlet);
iounmap(host->base);
host_free:
mmc_free_host(mmc);
out:
return ret;
}
mmc->caps |= MMC_CAP_SDIO_IRQ;这个写了应该是设置的。我发现我们公司自己使用的TF卡座是没有这个引脚的。先不管移远的测试板问题。解决下自己的板子吧,试试可不可。那我们看看另外芯片的驱动吧。我卡开了vub300.c,因为这是usb转SDIO的芯片,我了解所以看看。找它的probe代码如下
static int vub300_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{ /* NOT irq */
struct vub300_mmc_host *vub300;
struct usb_host_interface *iface_desc;
struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
int i;
int retval = -ENOMEM;
struct urb *command_out_urb;
struct urb *command_res_urb;
struct mmc_host *mmc;
char manufacturer[48];
char product[32];
char serial_number[32];
usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
sizeof(manufacturer));
usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
sizeof(serial_number));
dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
udev->descriptor.idVendor, udev->descriptor.idProduct,
manufacturer, product, serial_number);
command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!command_out_urb) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for command_out_urb\n");
goto error0;
}
command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!command_res_urb) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for command_res_urb\n");
goto error1;
}
/* this also allocates memory for our VUB300 mmc host device */
mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
if (!mmc) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for the mmc_host\n");
goto error4;
}
/* MMC core transfer sizes tunable parameters */
mmc->caps = 0;
if (!force_1_bit_data_xfers)
mmc->caps |= MMC_CAP_4_BIT_DATA;
if (!force_polling_for_irqs)
mmc->caps |= MMC_CAP_SDIO_IRQ;
mmc->caps |= MMC_CAP_NEEDS_POLL;
/*
* MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
* for devices which results in spurious CMD7's being
* issued which stops some SDIO cards from working
*/
if (limit_speed_to_24_MHz) {
mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
mmc->f_max = 24000000;
dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
} else {
mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
mmc->f_max = 48000000;
}
mmc->f_min = 200000;
mmc->max_blk_count = 511;
mmc->max_blk_size = 512;
mmc->max_segs = 128;
if (force_max_req_size)
mmc->max_req_size = force_max_req_size * 1024;
else
mmc->max_req_size = 64 * 1024;
mmc->max_seg_size = mmc->max_req_size;
mmc->ocr_avail = 0;
mmc->ocr_avail |= MMC_VDD_165_195;
mmc->ocr_avail |= MMC_VDD_20_21;
mmc->ocr_avail |= MMC_VDD_21_22;
mmc->ocr_avail |= MMC_VDD_22_23;
mmc->ocr_avail |= MMC_VDD_23_24;
mmc->ocr_avail |= MMC_VDD_24_25;
mmc->ocr_avail |= MMC_VDD_25_26;
mmc->ocr_avail |= MMC_VDD_26_27;
mmc->ocr_avail |= MMC_VDD_27_28;
mmc->ocr_avail |= MMC_VDD_28_29;
mmc->ocr_avail |= MMC_VDD_29_30;
mmc->ocr_avail |= MMC_VDD_30_31;
mmc->ocr_avail |= MMC_VDD_31_32;
mmc->ocr_avail |= MMC_VDD_32_33;
mmc->ocr_avail |= MMC_VDD_33_34;
mmc->ocr_avail |= MMC_VDD_34_35;
mmc->ocr_avail |= MMC_VDD_35_36;
mmc->ops = &vub300_mmc_ops;
vub300 = mmc_priv(mmc);
vub300->mmc = mmc;
vub300->card_powered = 0;
vub300->bus_width = 0;
vub300->cmnd.head.block_size[0] = 0x00;
vub300->cmnd.head.block_size[1] = 0x00;
vub300->app_spec = 0;
mutex_init(&vub300->cmd_mutex);
mutex_init(&vub300->irq_mutex);
vub300->command_out_urb = command_out_urb;
vub300->command_res_urb = command_res_urb;
vub300->usb_timed_out = 0;
vub300->dynamic_register_count = 0;
for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
vub300->fn[i].offload_point = 0;
vub300->fn[i].offload_count = 0;
}
vub300->total_offload_count = 0;
vub300->irq_enabled = 0;
vub300->irq_disabled = 0;
vub300->irqs_queued = 0;
for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
vub300->sdio_register[i++].activate = 0;
vub300->udev = udev;
vub300->interface = interface;
vub300->cmnd_res_ep = 0;
vub300->cmnd_out_ep = 0;
vub300->data_inp_ep = 0;
vub300->data_out_ep = 0;
for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
vub300->fbs[i] = 512;
/*
* set up the endpoint information
*
* use the first pair of bulk-in and bulk-out
* endpoints for Command/Response+Interrupt
*
* use the second pair of bulk-in and bulk-out
* endpoints for Data In/Out
*/
vub300->large_usb_packets = 0;
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
struct usb_endpoint_descriptor *endpoint =
&iface_desc->endpoint[i].desc;
dev_info(&vub300->udev->dev,
"vub300 testing %s EndPoint(%d) %02X\n",
usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
"UNKNOWN", i, endpoint->bEndpointAddress);
if (endpoint->wMaxPacketSize > 64)
vub300->large_usb_packets = 1;
if (usb_endpoint_is_bulk_in(endpoint)) {
if (!vub300->cmnd_res_ep) {
vub300->cmnd_res_ep =
endpoint->bEndpointAddress;
} else if (!vub300->data_inp_ep) {
vub300->data_inp_ep =
endpoint->bEndpointAddress;
} else {
dev_warn(&vub300->udev->dev,
"ignoring"
" unexpected bulk_in endpoint");
}
} else if (usb_endpoint_is_bulk_out(endpoint)) {
if (!vub300->cmnd_out_ep) {
vub300->cmnd_out_ep =
endpoint->bEndpointAddress;
} else if (!vub300->data_out_ep) {
vub300->data_out_ep =
endpoint->bEndpointAddress;
} else {
dev_warn(&vub300->udev->dev,
"ignoring"
" unexpected bulk_out endpoint");
}
} else {
dev_warn(&vub300->udev->dev,
"vub300 ignoring EndPoint(%d) %02X", i,
endpoint->bEndpointAddress);
}
}
if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
vub300->data_inp_ep && vub300->data_out_ep) {
dev_info(&vub300->udev->dev,
"vub300 %s packets"
" using EndPoints %02X %02X %02X %02X\n",
vub300->large_usb_packets ? "LARGE" : "SMALL",
vub300->cmnd_out_ep, vub300->cmnd_res_ep,
vub300->data_out_ep, vub300->data_inp_ep);
/* we have the expected EndPoints */
} else {
dev_err(&vub300->udev->dev,
"Could not find two sets of bulk-in/out endpoint pairs\n");
retval = -EINVAL;
goto error5;
}
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
GET_HC_INF0,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, 0x0000, &vub300->hc_info,
sizeof(vub300->hc_info), HZ);
if (retval < 0)
goto error5;
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
if (retval < 0)
goto error5;
dev_info(&vub300->udev->dev,
"operating_mode = %s %s %d MHz %s %d byte USB packets\n",
(mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
(mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
mmc->f_max / 1000000,
pad_input_to_usb_pkt ? "padding input data to" : "with",
vub300->large_usb_packets ? 512 : 64);
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
GET_SYSTEM_PORT_STATUS,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, 0x0000, &vub300->system_port_status,
sizeof(vub300->system_port_status), HZ);
if (retval < 0) {
goto error4;
} else if (sizeof(vub300->system_port_status) == retval) {
vub300->card_present =
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
vub300->read_only =
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
} else {
goto error4;
}
usb_set_intfdata(interface, vub300);
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
kref_init(&vub300->kref);
init_timer(&vub300->sg_transfer_timer);
vub300->sg_transfer_timer.data = (unsigned long)vub300;
vub300->sg_transfer_timer.function = vub300_sg_timed_out;
kref_get(&vub300->kref);
init_timer(&vub300->inactivity_timer);
vub300->inactivity_timer.data = (unsigned long)vub300;
vub300->inactivity_timer.function = vub300_inactivity_timer_expired;
vub300->inactivity_timer.expires = jiffies + HZ;
add_timer(&vub300->inactivity_timer);
if (vub300->card_present)
dev_info(&vub300->udev->dev,
"USB vub300 remote SDIO host controller[%d]"
"connected with SD/SDIO card inserted\n",
interface_to_InterfaceNumber(interface));
else
dev_info(&vub300->udev->dev,
"USB vub300 remote SDIO host controller[%d]"
"connected with no SD/SDIO card inserted\n",
interface_to_InterfaceNumber(interface));
mmc_add_host(mmc);
return 0;
error5:
mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
*/
error4:
usb_free_urb(command_res_urb);
error1:
usb_free_urb(command_out_urb);
error0:
usb_put_dev(udev);
return retval;
}
看了这么一句话
mmc->caps |= MMC_CAP_NEEDS_POLL;
/*
* MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
* for devices which results in spurious CMD7's being
* issued which stops some SDIO cards from working
*/
可以这样检测啊,那我就改改试试。到了我的板子上依旧无效。算了还是继续解决测试板上的问题吧。这块板子有接DETECTION引脚啊,会不会是bsp文件里没有初始化啊。去看看到ql-ol-sdk/ql-ol-kernel/arch/arm/boot/dts/qcom下找到mdm9607-mtp.dtsi文件看看。
&sdhc_2 {
/*vdd-supply = <&sdcard_ext_vreg>;*/
qcom,vdd-voltage-level = <2850000 2850000>;
qcom,vdd-current-level = <15000 400000>;
vdd-io-supply = <&mdm9607_l13>;
qcom,vdd-io-always-on; //20170915,add by cullen
qcom,vdd-io-voltage-level = <1800000 2850000>;
qcom,vdd-io-current-level = <200 50000>;
#address-cells = <0>;
interrupt-parent = <&sdhc_2>;
interrupts = <0 1 2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xffffffff>;
interrupt-map = <0 &intc 0 125 0
1 &intc 0 221 0
2 &tlmm_pinmux 26 0>;
interrupt-names = "hc_irq", "pwr_irq", "status_irq";
/*cd-gpios = <&tlmm_pinmux 26 0x1>;*/
qcom,nonhotplug;
pinctrl-names = "active", "sleep";
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
status = "ok";
};
哇发现了注释/*cd-gpios = <&tlmm_pinmux 26 0x1>;*/我去看看硬件引脚
原来移远注释掉了......,取消注释编译内核成功了。
那我自己公司的板子只能改SD卡座的封装了。