SDIO驱动(13)card的初始化
2017-05-29 17:24
190 查看
/* * Starting point for SDIO card init. */ int mmc_attach_sdio(struct mmc_host *host) { int err, i, funcs; u32 ocr; struct mmc_card *card; BUG_ON(!host); WARN_ON(!host->claimed); err = mmc_send_io_op_cond(host, 0, &ocr); if (err) return err; mmc_attach_bus(host, &mmc_sdio_ops); if (host->ocr_avail_sdio) host->ocr_avail = host->ocr_avail_sdio; /* * Sanity check the voltages that the card claims to * support. */ if (ocr & 0x7F) { printk(KERN_WARNING "%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; } host->ocr = mmc_select_voltage(host, ocr); /* * Can we support the voltage(s) of the card(s)? */ if (!host->ocr) { err = -EINVAL; goto err; } /* * Detect and init the card. */ err = mmc_sdio_init_card(host, host->ocr, NULL, 0); if (err) goto err; card = host->card; /* * Enable runtime PM only if supported by host+card+board */ if (host->caps & MMC_CAP_POWER_OFF_CARD) { /* * Let runtime PM core know our card is active */ err = pm_runtime_set_active(&card->dev); if (err) goto remove; /* * Enable runtime PM for this card */ pm_runtime_enable(&card->dev); } /* * The number of functions on the card is encoded inside * the ocr. */ funcs = (ocr & 0x70000000) >> 28; card->sdio_funcs = 0; /* * Initialize (but don't add) all present functions. */ for (i = 0; i < funcs; i++, card->sdio_funcs++) { err = sdio_init_func(host->card, i + 1); if (err) goto remove; /* * Enable Runtime PM for this func (if supported) */ if (host->caps & MMC_CAP_POWER_OFF_CARD) pm_runtime_enable(&card->sdio_func[i]->dev); } /* * First add the card to the driver model... */ mmc_release_host(host); err = mmc_add_card(host->card); if (err) goto remove_added; /* * ...then the SDIO functions. */ for (i = 0;i < funcs;i++) { err = sdio_add_func(host->card->sdio_func[i]); if (err) goto remove_added; } mmc_claim_host(host); return 0; remove_added: /* Remove without lock if the device has been added. */ mmc_sdio_remove(host); mmc_claim_host(host); remove: /* And with lock if it hasn't been added. */ mmc_release_host(host); if (host->card) mmc_sdio_remove(host); mmc_claim_host(host); err: mmc_detach_bus(host); printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", mmc_hostname(host), err); return err; }
13行mmc_send_io_op_cond,通过CMD5查询card支持的操作电压,CMD5是sdio特有的,所以如果对该命令没有反应说明卡槽里的是sd/mmc卡。由于命令发送函数结构大体差不离,所以就不列出mmc_send_io_op_cond函数的具体内容,来看CMD5:
OCR-Operation Conditions Register,card支持的最小和最低电压,这24bits的定义在“SDIO驱动(12)card的扫描流程”有详细列出。mmc_send_io_op_cond执行过后,变量ocr的内容为:
C:如果为1的话,说明卡已经准备就绪ready。
Number of I/O functions:card支持的I/O总数,范围0~7。
Memory Present:如果为0说明card仅仅是一个I/O卡;1说明card还支持SD memory。
Stuff bits:保留,值为0。
I/O OCR:card返回的Voltage support list。
17行mmc_attach_bus,为每一个host分配独有的总线handler:
/* * Assign a mmc bus handler to a host. Only one bus handler may control a * host at any given time. */ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) { unsigned long flags; BUG_ON(!host); BUG_ON(!ops); WARN_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); BUG_ON(host->bus_ops); BUG_ON(host->bus_refs); host->bus_ops = ops; host->bus_refs = 1; host->bus_dead = 0; spin_unlock_irqrestore(&host->lock, flags); }9、10行的检测是防止NULL指针,16、17行防止对host重复执行attach bus,之前说过如果检测出现异常系统会panic。
12行,记得吧在进入之前可是执行过独占访问设置的:
mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) break; if (freqs[i] < host->f_min) break; } mmc_release_host(host);关于sdio总线的mmc_sdio_ops,之前分析过它的detect函数实现,其他成员实现就略过不提了。
25~30行,card返回的ocr参数检测,防止出现不支持的电压值。不过按照spec,保留位占8个bits,难道不是应该if (ocr & 0xFF) {}吗?
32行mmc_select_voltage,选择host和card都支持的最低操作电压:
/* * Mask off any voltages we don't support and select * the lowest voltage */ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) { int bit; ocr &= host->ocr_avail; bit = ffs(ocr); if (bit) { bit -= 1; ocr &= 3 << bit; host->ios.vdd = bit; mmc_set_ios(host); } else { pr_warning("%s: host doesn't support card's voltages\n", mmc_hostname(host)); ocr = 0; } return ocr; }9行与过之后就是host、card都支持的电压设置,11行返回ocr中第一个bit是1的位置,注意范围计算方式[1,32]所以需要减去1,15行过后将mask off其他电压,不过这里3<<bit的话,如果ocr[bit+1]不为零,那么ocr[bit+1, bit]=0b11即bit+1位不被mask off。这是基于何种考虑?
45行正式开始card的初始化,复杂的函数:
/* * Handle the detection and initialisation of a card. * * In the case of a resume, "oldcard" will contain the card * we're trying to reinitialise. */ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard, int powered_resume) { struct mmc_card *card; int err; BUG_ON(!host); WARN_ON(!host->claimed); /* * Inform the card of the voltage */ if (!powered_resume) { err = mmc_send_io_op_cond(host, host->ocr, &ocr); if (err) goto err; } /* * For SPI, enable CRC as appropriate. */ if (mmc_host_is_spi(host)) { err = mmc_spi_set_crc(host, use_spi_crc); if (err) goto err; } /* * Allocate card structure. */ card = mmc_alloc_card(host, NULL); if (IS_ERR(card)) { err = PTR_ERR(card); goto err; } if (ocr & R4_MEMORY_PRESENT && mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) { card->type = MMC_TYPE_SD_COMBO; if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) { mmc_remove_card(card); return -ENOENT; } } else { card->type = MMC_TYPE_SDIO; if (oldcard && oldcard->type != MMC_TYPE_SDIO) { mmc_remove_card(card); return -ENOENT; } } /* * Call the optional HC's init_card function to handle quirks. */ if (host->ops->init_card) host->ops->init_card(host, card); /* * For native busses: set card RCA and quit open drain mode. */ if (!powered_resume && !mmc_host_is_spi(host)) { err = mmc_send_relative_addr(host, &card->rca); if (err) goto remove; /* * Update oldcard with the new RCA received from the SDIO * device -- we're doing this so that it's updated in the * "card" struct when oldcard overwrites that later. */ if (oldcard) oldcard->rca = card->rca; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } /* * Read CSD, before selecting the card */ if (!oldcard && card->type == MMC_TYPE_SD_COMBO) { err = mmc_sd_get_csd(host, card); if (err) return err; mmc_decode_cid(card); } /* * Select card, as all following commands rely on that. */ if (!powered_resume && !mmc_host_is_spi(host)) { err = mmc_select_card(card); if (err) goto remove; } if (card->quirks & MMC_QUIRK_NONSTD_SDIO) { /* * This is non-standard SDIO device, meaning it doesn't * have any CIA (Common I/O area) registers present. * It's host's responsibility to fill cccr and cis * structures in init_card(). */ mmc_set_clock(host, card->cis.max_dtr); if (card->cccr.high_speed) { mmc_card_set_highspeed(card); mmc_set_timing(card->host, MMC_TIMING_SD_HS); } goto finish; } /* * Read the common registers. */ err = sdio_read_cccr(card); if (err) goto remove; /* * Read the common CIS tuples. */ err = sdio_read_common_cis(card); if (err) goto remove; if (oldcard) { int same = (card->cis.vendor == oldcard->cis.vendor && card->cis.device == oldcard->cis.device); mmc_remove_card(card); if (!same) return -ENOENT; card = oldcard; } if (card->type == MMC_TYPE_SD_COMBO) { err = mmc_sd_setup_card(host, card, oldcard != NULL); /* handle as SDIO-only card if memory init failed */ if (err) { mmc_go_idle(host); if (mmc_host_is_spi(host)) /* should not fail, as it worked previously */ mmc_spi_set_crc(host, use_spi_crc); card->type = MMC_TYPE_SDIO; } else card->dev.type = &sd_type; } /* * If needed, disconnect card detection pull-up resistor. */ err = sdio_disable_cd(card); if (err) goto remove; /* * Switch to high-speed (if supported). */ err = sdio_enable_hs(card); if (err > 0) mmc_sd_go_highspeed(card); else if (err) goto remove; /* * Change to the card's maximum speed. */ mmc_set_clock(host, mmc_sdio_get_max_clock(card)); /* * Switch to wider bus (if supported). */ err = sdio_enable_4bit_bus(card); if (err > 0) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); else if (err) goto remove; finish: if (!oldcard) host->card = card; return 0; remove: if (!oldcard) mmc_remove_card(card); err: return err; }20行,之前的mmc_send_io_op_cond动作第二个参数为0,所以仅仅是探测一下;这里传入了ocr参数,那么将等待card状态ready后才返回。
28~32行的SPI接口操作方式不予关注。
37~41行,mmc_alloc_card创建一个card设备
43~51行,即上面提到的sdio+memory混合的卡,MMC框架对其定义的类型为MMC_TYPE_SD_COMBO。纯粹的sdio卡的类型为MMC_TYPE_SDIO。
64、65行,host controller提供了init_card回调的话则调用之,用来执行controller特定的card初始话。如果硬件厂商按照标准来的话自然不需要,但林子这么大难免有不按套路出牌的,无论怎么说该支持还得支持。
71行,通过CMD3获取card的地址(RCA),CMD3的响应为R6:
83行,bus有两种模式:
MMC_BUSMODE_OPENDRAIN: 该模式用于card的初始化。
MMC_BUSMODE_PUSHPULL: 进入传输状态前,设置bus模式为pushpull模式。
89~95行,sdio卡不支持该操作。
101行,发送CMD7选中card,在standby和transfer状态之间进行转换,此处转换到transfer状态。
106~121行,说的就是那些不按套路设计硬件的厂商的产品,由host填充时序参数。
126行,sdio_read_cccr读取CCCR(Card Common Control Registers)寄存器的值,这里有个关系需要知道:
1、CCCR位于卡的CIA区域;
2、CIA区域访问方式:host通过sdio专属命令CMD52、功能号0访问。
所以,看sdio_read_cccr函数:
static int sdio_read_cccr(struct mmc_card *card) { int ret; int cccr_vsn; unsigned char data; memset(&card->cccr, 0, sizeof(struct sdio_cccr)); // SDIO_CCCR_CCCR = 0 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); if (ret) goto out; cccr_vsn = data & 0x0f; if (cccr_vsn > SDIO_CCCR_REV_1_20) { printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", mmc_hostname(card->host), cccr_vsn); return -EINVAL; } card->cccr.sdio_vsn = (data & 0xf0) >> 4; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); if (ret) goto out; if (data & SDIO_CCCR_CAP_SMB) card->cccr.multi_block = 1; if (data & SDIO_CCCR_CAP_LSC) card->cccr.low_speed = 1; if (data & SDIO_CCCR_CAP_4BLS) card->cccr.wide_bus = 1; if (cccr_vsn >= SDIO_CCCR_REV_1_10) { ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); if (ret) goto out; if (data & SDIO_POWER_SMPC) card->cccr.high_power = 1; } if (cccr_vsn >= SDIO_CCCR_REV_1_20) { ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); if (ret) goto out; if (data & SDIO_SPEED_SHS) card->cccr.high_speed = 1; } out: return ret; }9行,mmc_io_rw_direct是CMD52的实现函数,其原型:
int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8 *out)
通过设置不同addr参数就可以读取相应寄存器信息。这部分内容完全就是spec的实现,参照spec即可理解。
133行,sdio_read_common_cis读取CIS(Card Information Structure)信息。这部分内容较多,只能单独列出,参见“SDIO驱动(14)card的CIS读取”。
137~145行,参数oldcard传进来的是NULL,所以不予关心。147~158行,MMC_TYPE_SD_COMBO混合卡也不关心。
163~185行,这部分函数作用及原理参考spec都很容易理解。
至此,mmc_sdio_init_card函数就分析完了。
接着看mmc_attach_sdio函数,53~65行,又是PM的东西,71~72行,解析出function numbers。
77~87行,每一个function作为一个device,由结构体sdio_func表征,挂在sdio总线下面;sdio_init_func函数用来完成创建并初始化它。
93行,添加card到系统中(device_add)并标志card为Present状态;101行,做同样的事情。
相关文章推荐
- linux驱动:音频驱动(三)ASoc之machine驱动及card初始化
- STM32F103 SDIO Sdcard驱动以及例程的问题
- SDIO驱动(12)card的扫描流程
- SDIO驱动(14)card的CIS读取及解析
- [转]基于linux-2.6.38.8内核的wifi驱动分析(SDIO)
- Zephyr OS 驱动篇之设备初始化顺序
- sdio 驱动
- 如何调整Linux内核启动中的驱动初始化顺序(zz)
- SDIO驱动总结
- volcanol_Linux_ 问题汇总系列_4_Thinkpad_E40_0578MDC_在Fedora 13 Linux(FC13)中如何安装无线网卡驱动
- linux串口驱动初始化
- 13、14、15章(类,类的初始化、赋值和析构,重载操作符和用户定义的转换)
- Fedora 13完美安装Nvidia官方驱动[转]
- linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)
- Linux设备驱动开发详解-Note(13)--- 字符设备驱动(2)
- 如何调整Linux内核启动中的驱动初始化顺序
- linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)
- 《Linux内核修炼之道》精华分享与讨论(13)——驱动开发三件宝:spec、datasheet与内核源码 .
- Linux 驱动分析--s3c6410 的SDIO驱动分析-bluedrum-ChinaUnix博客
- linux sd卡驱动分析,基于mini2440,sdio mmc sd卡驱动编写(2),一些初始化流程