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

        先感谢下这本书的作者,因为基本原理的了解都来自它。

在测试移远的内核时发现居然无法在开机后自动识别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卡。

                                   卡识别模式的状态可以用下面的状态图表示

     移远EC20中SD卡无法开机后自动识别是否拔插_第1张图片

                                     卡总线被激活后,主机就开始卡的初始化和识别处理。初始化处理从设置它的操作状态和设置OCR中的HCS比特位命令SD_SEND_OP_COND(ACMD41)开始。HCS比特位被设置为1表示主机支持高容量SD卡。HCS被设置为0表示主机不支持高容易SD卡。

                                      卡的初始化和识别更详细的流程

                                           移远EC20中SD卡无法开机后自动识别是否拔插_第2张图片

                                     卡的识别模式结束后,主机时钟fpp(数据传输时钟速率)将保持为Fod(卡识别模式下的时钟),因为有些卡对操作时钟有限制。主机必须发生SEND_CSD(CMD9)来获得卡规格数据寄存器内容,如块大小、卡容量。广播命令SET_DSR(CMD4)配置所有识别卡的驱动阶段。它对DSR寄存器进行编程以适应应用总线布局、总线上的卡数目和数据传输频率。

                                      SD卡数据传输模式下的状态图

移远EC20中SD卡无法开机后自动识别是否拔插_第3张图片

        二.了解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);
	} 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卡座的封装了。

你可能感兴趣的:(EC20)