先感谢下<linux系统移植>这本书的作者,因为基本原理的了解都来自它。

在测试移远的内核时发现居然无法在开机后自动识别SD卡。我这就纳闷了,于是去找原因。

一.先了解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卡的

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);} elsepr_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;elsemmc->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));elsedev_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 cullenqcom,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 01 &intc 0 221 02 &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卡座的封装了。

移远EC20中SD卡无法开机后自动识别是否拔插相关推荐

  1. 4G模块使用记录移远EC20、BC20

    目录 0. 概述 硬件连接 -- UART 休眠管脚的使用 硬件连接 -- USB USB线序定义 驱动安装 抓取模组log 模组型号和SIM卡 模组区别 本地卡和漫游卡 SIM卡和APN 1. EC ...

  2. 移远EC20设置RNDIS模式拨号上网

    背景 4G模块原本使用QMI方式拨号上网,客户反馈某种定制卡不能上网,切换下拨号模式看下设备能不能正常上网: 过程 openwrt中如果使用RNDIS模式上网需要在kernel配置中使能以下项: Km ...

  3. 海思3531添加移远EC20 4G模块

    在linux下加载驱动有两种常用方法:静态加载和动态加载. 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用.静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译和下载内核,效率 ...

  4. 树莓派CM4_TBOX扩展板(针对车机和工业应用)之移远EC20 4G模块的操作演示

    关键词:树莓派  CM4  TBOX  车机  数据终端  工业采集  RS485  CAN  4G  移远  即插即用  免驱  免拨号  IPv6  物联网 概述:TBOX是一款基于树莓派CM4的 ...

  5. ec20驱动_物联网基础:移远EC20固件升级

    使用移远 QFlash_V4.14 工具升级移远 EC20 4G模块固件 1 准备工作 1.1 EC20 USB驱动安装 安装过程参考移远官方手册:<Quectel_LTE&5G_Win ...

  6. 树莓派烧写OpenWrt系统后外接华为ME909或移远EC20 4G LTE模块实现4G软路由即MiFi

    By Mcuzone 关键词:OpenWrt  4G  LTE  软路由  华为ME909s  移远 EC20  树莓派  Raspberry  Pi  3B  4B  WiFi  热点  SSID ...

  7. OpenHarmony3.1适配移远EC20模组4G上网功能

    OpenHarmony3.1适配移远EC20模组4G上网功能 一.概述 通过阅读本篇文档,您将学习到如何适配移远EC20模组到OpenHarmony3.1(以下简称OHOS),并添加4G上网功能. 本 ...

  8. 【openwrt】使用4G模块 移远EC20/25(2)pppd拨号与配置

    [openwrt]使用4G模块 移远EC20/25 :2)pppd拨号与配置 参考 Raspberrypi -- 实现 EC20 4G模块PPP拨号上网_梦小羊的博客-CSDN博客 添加链接描述 == ...

  9. Hi3798移植4G模块(移远EC20)

    Hi3798移植4G模块(移远EC20) 一.前言 二.USB驱动修改 2.1 添加VID和PID信息 2.2 添加空包处理机制 2.3 添加复位重连机制 2.4 修改内核配置 三.GoBiNet测试 ...

  10. 4g模块注册上网 移远_移远EC20(4G模块)通过openwrt路由器拨号上网

    移远EC20是一个兼容性比较强的4G模块.我入手的这个是EC20 R2.1版本,pcie接口的,这个版本是增强版,支持最高150Mbps的下载速率,而普通的EC20只有100Mbps下载速率.这个是全 ...

最新文章

  1. SQLServer代理新建或者编辑作业报错
  2. 一种storyboard+swift实现页面跳转的方法
  3. access开发精要(14)-货币与数字类型格式(2)
  4. 牛客题霸 [链表中环的入口节点] C++题解/答案
  5. fastlane use_legacy_build_api true
  6. vue复选框默认被选中_vue .js绑定checkbox并获取、改变选中状态的实例
  7. hadoop 单机单间_初学Hadoop之单机模式环境搭建
  8. 谁说贾跃亭不还钱?人家已偿还超30亿美元的国内债务
  9. 在.NET Core 3.0 Preview上使用Windows窗体设计器
  10. mysql 分组group
  11. python中result的用法_Python中qutip用法示例详解
  12. [Android]Eclipse连不上模拟器的问题[emulator-5554 disconnected]
  13. 【poj1995】Raising Modulo Numbers
  14. 用Tornado实现web聊天室(前端采用vue+bootstrap)
  15. jzxx1107字符图形6-星号倒三角
  16. 哪吒票房超复联4,100行python代码抓取豆瓣短评,看看网友怎么说
  17. 读书笔记010:《伤寒论》- 足少阴肾经
  18. 数据结构与算法——红黑树(Red Black Tree)
  19. MathType批量修改公式字体和大小
  20. 改变xp开机和关机画面的方法

热门文章

  1. 从sql2016导出数据库到sql2014
  2. 2022最新软件设计师历年真题和答案解析分享!
  3. canoe Demo版本申请流程
  4. zk框架实现zul的js代码调用服务器java命令
  5. 【数据结构系列】严蔚敏C语言版算法实现并附带详细注释(逐步更新)
  6. tensorRt加速tensorflow模型推理(inception V3为例)
  7. 实现NeatUpload大文件上传和个性显示进度条
  8. springcloud中文手册API
  9. JAVA排序:快速排序算法
  10. 50个app帮你手机大换血!