以瑞芯微(rk)平台的代码解析,其他平台也类似,供其他同学参考学习.
参考:http://blog.chinaunix.net/uid-25445243-id-3885164.html

    int dw_mci_probe(struct dw_mci *host){const struct dw_mci_drv_data *drv_data = host->drv_data;int width, i, ret = 0;u32 fifo_size;int init_slots = 0;if (!host->pdata) {host->pdata = dw_mci_parse_dt(host); //解析dts中卡槽,队列深度,检测卡之前的延时(毫秒)if (IS_ERR(host->pdata)) {dev_err(host->dev, "platform data not available\n");return -EINVAL;}}if (host->pdata->num_slots < 1) {dev_err(host->dev,"Platform data must supply num_slots.\n");return -ENODEV;}host->biu_clk = devm_clk_get(host->dev, "biu"); //获取总线接口单元时钟 biu=bus interface unit clockif (IS_ERR(host->biu_clk)) {dev_dbg(host->dev, "biu clock not available\n");} else {ret = clk_prepare_enable(host->biu_clk); //clk使能if (ret) {dev_err(host->dev, "failed to enable biu clock\n");return ret;}}host->ciu_clk = devm_clk_get(host->dev, "ciu"); //获取sd卡接口时钟 ciu=card interface unit clockif (IS_ERR(host->ciu_clk)) {dev_dbg(host->dev, "ciu clock not available\n");host->bus_hz = host->pdata->bus_hz;} else {ret = clk_prepare_enable(host->ciu_clk);if (ret) {dev_err(host->dev, "failed to enable ciu clock\n");goto err_clk_biu;}if (host->pdata->bus_hz) {ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);if (ret)dev_warn(host->dev,"Unable to set bus rate to %uHz\n",host->pdata->bus_hz);}host->bus_hz = clk_get_rate(host->ciu_clk); //获得卡的设备时钟频率赋值给bus_hz}if (!host->bus_hz) {dev_err(host->dev,"Platform data must supply bus speed\n");ret = -ENODEV;goto err_clk_ciu;}if (drv_data && drv_data->init) {  //调用host/dw_mmc-rockchip.c中的回调函数.init = dw_mci_rockchip_init,ret = drv_data->init(host);if (ret) {dev_err(host->dev,"implementation specific init failed\n");goto err_clk_ciu;}}if (drv_data && drv_data->setup_clock) { //同上也是回调函数ret = drv_data->setup_clock(host);if (ret) {dev_err(host->dev,"implementation specific clock setup failed\n");goto err_clk_ciu;}}setup_timer(&host->cmd11_timer,dw_mci_cmd11_timer, (unsigned long)host); //内核定时机制,主要设置host->cmd11_timer的回调, \        host->cmd11_timer->function = dw_mci_cmd11_timer;  host->cmd11_timer->data =hosthost->quirks = host->pdata->quirks;setup_timer(&host->cto_timer,dw_mci_cto_timer, (unsigned long)host);if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)setup_timer(&host->dto_timer,dw_mci_dto_timer, (unsigned long)host);if (host->quirks & DW_MCI_QUIRK_BROKEN_XFER)setup_timer(&host->xfer_timer,dw_mci_xfer_timer, (unsigned long)host);spin_lock_init(&host->lock);     //初始化自旋锁spin_lock_init(&host->irq_lock); //初始化自旋锁INIT_LIST_HEAD(&host->queue);  //初始化链表/** Get the host data width - this assumes that HCON has been set with* the correct values.*/i = SDMMC_GET_HDATA_WIDTH(mci_readl(host, HCON));if (!i) {host->push_data = dw_mci_push_data16; //操作数据函数集合,测函数中赋值的收发函数,这里根据数据类型,总共有三种,包括16位、32位和64位的收发 接收到的长度是以字节为单位的,所以16位的除以2,如果是32位的就右移两位,除以4,以此类推host->pull_data = dw_mci_pull_data16; //width = 16;host->data_shift = 1;} else if (i == 2) {host->push_data = dw_mci_push_data64;host->pull_data = dw_mci_pull_data64;width = 64;host->data_shift = 3;} else {/* Check for a reserved value, and warn if it is */WARN((i != 1),"HCON reports a reserved host data width!\n""Defaulting to 32-bit access.\n");host->push_data = dw_mci_push_data32;host->pull_data = dw_mci_pull_data32;width = 32;host->data_shift = 2;}/* Reset all blocks */if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) //sd卡复位,设置控制寄存器,等待超时时间内return -ENODEV;host->dma_ops = host->pdata->dma_ops;dw_mci_init_dma(host);  // dma初始化/* Clear the interrupts for the host controller */mci_writel(host, RINTSTS, 0xFFFFFFFF);mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first *//* Put in max timeout */mci_writel(host, TMOUT, 0xFFFFFFFF);/** FIFO threshold settings  RxMark  = fifo_size / 2 - 1,*                          Tx Mark = fifo_size / 2 DMA Size = 8*/if (!host->pdata->fifo_depth) {/** Power-on value of RX_WMark is FIFO_DEPTH-1, but this may* have been overwritten by the bootloader, just like we're* about to do, so if you know the value for your hardware, you* should put it in the platform data.*/fifo_size = mci_readl(host, FIFOTH);fifo_size = 1 + ((fifo_size >> 16) & 0xfff);} else {fifo_size = host->pdata->fifo_depth;}host->fifo_depth = fifo_size;host->fifoth_val =SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);mci_writel(host, FIFOTH, host->fifoth_val);/* disable clock to CIU */mci_writel(host, CLKENA, 0);mci_writel(host, CLKSRC, 0);/** In 2.40a spec, Data offset is changed.* Need to check the version-id and set data-offset for DATA register.*/host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));dev_info(host->dev, "Version ID is %04x\n", host->verid);printk("hdj sdmmc Version ID is %04x\n", host->verid);if (host->verid < DW_MMC_240A)host->fifo_reg = host->regs + DATA_OFFSET;elsehost->fifo_reg = host->regs + DATA_240A_OFFSET;tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);  //操作函数集合,回调函数赋值给host->tasklet变量ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,  //往下看host->irq_flags, "dw-mci", host);if (ret)goto err_dmaunmap;if (host->pdata->num_slots)host->num_slots = host->pdata->num_slots;elsehost->num_slots = SDMMC_GET_SLOT_NUM(mci_readl(host, HCON));/** Enable interrupts for command done, data over, data empty,* receive ready and error such as transmit, receive timeout, crc error*/mci_writel(host, RINTSTS, 0xFFFFFFFF);mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |SDMMC_INT_TXDR | SDMMC_INT_RXDR |DW_MCI_ERROR_FLAGS);/* Enable mci interrupt */mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);dev_info(host->dev,"DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n",host->irq, width, fifo_size);/* We need at least one slot to succeed */for (i = 0; i < host->num_slots; i++) {ret = dw_mci_init_slot(host, i);  //slot初始化,申请host,识别sd卡,读取sd卡cid,会调到core层if (ret)dev_dbg(host->dev, "slot %d init failed\n", i);elseinit_slots++;}if (init_slots) {dev_info(host->dev, "%d slots initialized\n", init_slots);} else {dev_dbg(host->dev,"attempted to initialize %d slots, but failed on all\n",host->num_slots);goto err_dmaunmap;}/* Now that slots are all setup, we can enable card detect */dw_mci_enable_cd(host);if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");return 0;}
    static irqreturn_t dw_mci_interrupt(int irq, void *dev_id){struct dw_mci *host = dev_id;u32 pending;int i;unsigned long irqflags;pending = mci_readl(host, MINTSTS); /* read-only mask reg  读取屏蔽中断状态寄存器 DMMC_MINTSTS *//** DTO fix - version 2.10a and below, and only if internal DMA* is configured.*/if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {if (!pending &&((mci_readl(host, STATUS) >> 17) & 0x1fff))pending |= SDMMC_INT_DATA_OVER;}if (pending) {/* Check volt switch first, since it can look like an error */if ((host->state == STATE_SENDING_CMD11) && //CMD11电压切换(pending & SDMMC_INT_VOLT_SWITCH)) {mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);pending &= ~SDMMC_INT_VOLT_SWITCH;/** Hold the lock; we know cmd11_timer can't be kicked* off after the lock is released, so safe to delete.*/spin_lock_irqsave(&host->irq_lock, irqflags);dw_mci_cmd_interrupt(host, pending);  //调用软中断taskler_schedulespin_unlock_irqrestore(&host->irq_lock, irqflags);del_timer(&host->cmd11_timer);}if (pending & DW_MCI_CMD_ERROR_FLAGS) {  命令错误,响应错误,响应CRC错误,响应超时错误spin_lock_irqsave(&host->irq_lock, irqflags);del_timer(&host->cto_timer);mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); host->cmd_status = pending;if ((host->quirks & DW_MCI_QUIRK_BROKEN_XFER) &&host->dir_status == DW_MCI_RECV_STATUS)del_timer(&host->xfer_timer);smp_wmb(); /* drain writebuffer */set_bit(EVENT_CMD_COMPLETE, &host->pending_events);spin_unlock_irqrestore(&host->irq_lock, irqflags);}if (pending & DW_MCI_DATA_ERROR_FLAGS) {    // //数据错误,数据读超时,CRC错误,主设备超时,起始位错误,最后一位错误/* if there is an error report DATA_ERROR */mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);host->data_status = pending;smp_wmb(); /* drain writebuffer */set_bit(EVENT_DATA_ERROR, &host->pending_events);tasklet_schedule(&host->tasklet);   //调度软中断函数,执行EVENT_DATA_ERROR分支}if (pending & SDMMC_INT_DATA_OVER) {  //数据传输结束中断spin_lock_irqsave(&host->irq_lock, irqflags);if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)del_timer(&host->dto_timer);mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);if (!host->data_status)host->data_status = pending;smp_wmb(); /* drain writebuffer */if (host->dir_status == DW_MCI_RECV_STATUS) {if (host->sg != NULL)dw_mci_read_data_pio(host, true); //读数据}set_bit(EVENT_DATA_COMPLETE, &host->pending_events);tasklet_schedule(&host->tasklet);spin_unlock_irqrestore(&host->irq_lock, irqflags);}if (pending & SDMMC_INT_RXDR) {   //收数据中断mci_writel(host, RINTSTS, SDMMC_INT_RXDR);if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)dw_mci_read_data_pio(host, false);}if (pending & SDMMC_INT_TXDR) {  //发数据中断mci_writel(host, RINTSTS, SDMMC_INT_TXDR);if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)dw_mci_write_data_pio(host); 写数据}if (pending & SDMMC_INT_CMD_DONE) { // //命令结束中断spin_lock_irqsave(&host->irq_lock, irqflags);mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);dw_mci_cmd_interrupt(host, pending);spin_unlock_irqrestore(&host->irq_lock, irqflags);}if (pending & SDMMC_INT_CD) {   //发现sd卡后mci_writel(host, RINTSTS, SDMMC_INT_CD);dw_mci_handle_cd(host); //卡插入或拔出的处理函数}/* Handle SDIO Interrupts */for (i = 0; i < host->num_slots; i++) {struct dw_mci_slot *slot = host->slot[i];if (!slot)continue;if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { //判断sdio设备mci_writel(host, RINTSTS,SDMMC_INT_SDIO(slot->sdio_id));mmc_signal_sdio_irq(slot->mmc); //唤醒中断线程}}}if (host->use_dma != TRANS_MODE_IDMAC)return IRQ_HANDLED;/* Handle IDMA interrupts */if (host->dma_64bit_address == 1) {pending = mci_readl(host, IDSTS64);  //读取内部DMA状态寄存器if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |SDMMC_IDMAC_INT_RI);mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))host->dma_ops->complete((void *)host);}} else {pending = mci_readl(host, IDSTS);if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |SDMMC_IDMAC_INT_RI);mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))host->dma_ops->complete((void *)host);}}return IRQ_HANDLED;}

Linux SD卡/SDIO驱动开发-dw_mci_probe相关推荐

  1. Linux SD卡/SDIO驱动开发0-基本知识

    文章目录 Linux驱动子系统-sdio子系统 sdio系统概述 判断sd卡是否识别 判断sdio wifi是否识别 sd协议 SD BUS SPI BUS 硬件接口: 调试的问题 sdmmc接口使用 ...

  2. cmd52命令发送 mmc_乾坤合一~Linux SD/MMC/SDIO驱动分析(上)

    一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(MultimediaCard) SD 是一种 flash memory card 的标准,也就是一般常见的 SD 记忆 ...

  3. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  4. Linux SD卡驱动

    二.MMC/SD介绍及SDI主机控制器 首先我们来理清几个概念: MMC:(Multi Media Card)由西门子公司和首推CF的SanDisk于1997年推出的多媒体记忆卡标准. SD:(Sec ...

  5. linux sd卡驱动流程图,SD卡驱动(详细介绍,不明白的人可以仔细看看了.有流程图)-转-OpenEdv-开源电子网...

    ffice ffice" /> 一.SD/MMC卡介绍 1.1.什么是MMC卡 MMC:MMC就是MultiMediaCard的缩写,即多媒体卡.它是一种非易失性存储器件,体积小巧(2 ...

  6. SD卡的驱动(linux操作系统下)

    emmc读写速度慢:是1线,还是4,8线,emmc和控制器本身支持的最高速率,还有dts的配置,cache(sync)是否有影响:回写,调度. s3cmci_probe->mmc_alloc_h ...

  7. cmd52命令发送 mmc_Linux SD/MMC/SDIO驱动分析(新)

    一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(MultimediaCard) SD 是一种 flash memory card 的标准,也就是一般常见的 SD 记忆 ...

  8. cmd的发送 mmc_Linux SD/MMC/SDIO驱动分析

    一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(MultimediaCard) SD 是一种 flash memory card 的标准,也就是一般常见的 SD 记忆 ...

  9. SD Nand 与 SD卡 SDIO模式应用流程

    SD Nand/SD卡 SDIO模式应用流程 文章目录 SD Nand/SD卡 SDIO模式应用流程 1. 前言 1.1 参考文档 1.2 概述 2. Response响应类型及格式 3. 各步骤流程 ...

最新文章

  1. 五分钟搭建一个基于BERT的NER模型
  2. 解决MySQL导入数据时遇到secure-file-priv的问题
  3. OpenGL中关于坐标系原点在左上角还是左下角的一些整理
  4. 角逐同城货运,快狗打车抢跑上市
  5. Java多线程(4)--线程的同步解决线程安全问题
  6. 小程序反编译 g is not defined_培生幼儿启蒙英语 Level B | 小牧羊女在哪?
  7. 用asp.net+Jquery+Ajax+sqlserver编写的 (英语六级记单词)
  8. 谷歌将于11月修改服务条款
  9. AI产品,如何做好从零到一
  10. sklearn 2.回归树
  11. java 图像渲染_对具有大量图像的视图执行本机渲染性能
  12. 13.nginx 源码目录及配置
  13. SQL Server 何时将“脏页”回写到硬盘
  14. Java 读取txt文件生成Word文档
  15. Python如何抓取APP数据?抓包工具Fiddler介绍
  16. android接口回调!为什么有人说Android开发不再吃香?内含福利
  17. excel学习笔记(一)
  18. SoundPool播放系统提示音
  19. Cisco 7600系列Supervisor Engine 720-3BXL
  20. bzoj3585 mex

热门文章

  1. 热烈祝贺重庆大学75周年校庆
  2. 小升初数学知识体系梳理
  3. ACMUG活动回顾 | MySQL创始人见面会技术分享会圆满结束
  4. python一元二次方程组
  5. 关于计算机未来理想,关于未来与梦想的作文
  6. matlab绘制那奎斯特曲线和bode图
  7. 揭秘刘德华感恩立志的少年时光
  8. 一张图,理清微服务架构路线(收藏)
  9. Golang停止ticker断续器
  10. 自动发货-用千牛如何做到发货号自动转接人工号