您的位置:首页 > 移动开发 > Android开发

Android mtk sd卡调试

2014-10-22 15:44 423 查看
sd.c

static u32 msdc_sd1_power(u32 on, MT65XX_POWER_VOLTAGE powerVolt)

{

//libin modify for M1-21 on 20120907

#ifdef MTK_EMMC_SUPPORT  // sd1 change to VGP      

    //msdc_ldo_power(on, MT65XX_POWER_LDO_VGP, powerVolt, &g_vgp);

    msdc_ldo_power(on, MT65XX_POWER_LDO_VMC, powerVolt, &g_vmc);   

#else  // VMC 

msdc_ldo_power(on, MT65XX_POWER_LDO_VGP, powerVolt, &g_vmc);

    //msdc_ldo_power(on, MT65XX_POWER_LDO_VMC, powerVolt, &g_vmc);    

#endif 

      msdc_ldo_power(on, MT65XX_POWER_LDO_VMCH, powerVolt, &g_vmch);     

    return 0;     

}

更改board.c

struct msdc_hw msdc1_hw = {

    .clk_src        = 1,

    .cmd_edge       = MSDC_SMPL_FALLING,

    .data_edge      = MSDC_SMPL_FALLING,

    .clk_drv        = 0,

    .cmd_drv        = 0,

    .dat_drv        = 0,

    .data_pins      = 4,

    .data_offset    = 0,

    .flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED, //libin add for M1-21 on 20120908

//.flags          = MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE| MSDC_HIGHSPEED, //libin del

};

参考如下:

1. 检查硬件设计是否按照参考设计进行;

2. 检查SD Host端供电,即DVDD_MC1的连接;

检查代码:\mediatek\platform\mt6575\kernel\drivers\mmc-host\sd.c

static u32 msdc_sd1_power(u32 on, MT65XX_POWER_VOLTAGE powerVolt)



#ifdef MTK_EMMC_SUPPORT // sd1 change to VGP 

msdc_ldo_power(on, MT65XX_POWER_LDO_VGP, powerVolt, &g_vgp); 

#else // VMC 

msdc_ldo_power(on, MT65XX_POWER_LDO_VMC, powerVolt, &g_vmc);

 #endif 

msdc_ldo_power(on, MT65XX_POWER_LDO_VMCH, powerVolt, &g_vmch);

 return 0; 

}

3. SD卡是否支持热插拔

根据MSDC1_INSI的连接情况检查\mediatek\custom{project_name}\kernel\core\src\board.c中热插拔的标志(MSDC_CD_PIN_EN | MSDC_REMOVABLE);

支持热插拔,则添加标志,并配置对应的GPIO;

不支持热插拔,则去除标志,无需配置对应的GPIO。

struct msdc_hw msdc1_hw = { 

.clk_src = 1, .cmd_edge = MSDC_SMPL_FALLING, .data_edge = MSDC_SMPL_FALLING, .clk_drv = 0, .cmd_drv = 0, .dat_drv = 0, .data_pins = 4, .data_offset = 0, .flags = MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_HIGHSPEED|MSDC_SPE | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
};

mediatek\custom\benrui15_ics2\kernel\core\src\board.c

.flags          = MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED | MSDC_CD_PIN_EN | MSDC_REMOVABLE,//|MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN ,//| MSDC_CD_PIN_EN | MSDC_REMOVABLE,

一. SD卡的基本知识:

 SD卡有9个pin脚(micro-SD为8个,少一个接地pin脚),如图所示,

 





SD的数据传输方式有两种,普通SD模式和SPI模式,以SD模式为例,9个pin脚分别是VDD,VSS,CLK,以及我们需要关注的一根指令线CMD,4根数据线DAT0~DAT3。

分类:

按存储大小,普通SD卡(<=2GB,支持FAT12/FAT16),HCSD卡(>2GB,<=32GB,支持FAT32)

按体积大小,普通SD卡,mini-SD卡,micro-SD卡(TF卡)

速度

默认模式: 12.5MB/s

高速模式: 25MB/s

二. SD卡在MTK6573中的架构

       涉及到的文件有:mediatek/platform/mt6573/kernel/drivers/mmc-host/sd.c

                                       mediatek/platform/mt6573/kernel/drivers/mmc-host/mt6573_sdc.c

        下面就整个驱动的流程过一下:

         系统起来的时候执行 static int __init mt6573_sd_init(void) 在这个函数里最重要的是执行platform_driver_register(&mt6573_sd_driver),即注册到内核的虚拟总线上,注册的原则是把驱动mt6573_sd_driver各参数进行初始化。

          下面进入变量mt6573_sd_driver各成员的初始化。其中最重要的成员是mt6573_sd_probe的执行。当在虚拟platform总线上driver和device的名字"mt6573-sd"相匹配时即执行probe函数。

下面先看看文件mt6573_sdc.c中的static struct platform_device mt6573_device_sd[] =

{

    {

        .name           = "mt6573-sd",

        .id             = 0,

        .num_resources  = ARRAY_SIZE(mt6573_resource_sd0),

        .resource       = mt6573_resource_sd0,

        .dev = {

            .platform_data = &mt6573_sd0_hw,

        },

    },

从这个结构体可以得出platform_device和platform_driver的name是相同的,所以会遍历到执行probe函数,这个结构体中有个重要的参数mt6573_sd0_hw,这个成员即是SD卡的初始状态值:

struct mt6573_sd_host_hw mt6573_sd0_hw = {

    .clk_src        = MSDC_CLKSRC_98MHZ,

    .cmd_edge       = EDGE_RISING,

    .data_edge      = EDGE_RISING,

    .cmd_odc        = MSDC_ODC_8MA,

    .data_odc       = MSDC_ODC_8MA,

    .cmd_slew_rate  = MSDC_ODC_SLEW_SLOW,

    .data_slew_rate = MSDC_ODC_SLEW_SLOW,

    .cmd_pull_res   = MSDC_PULL_RES_23K,

    .dat_pull_res   = MSDC_PULL_RES_23K,

    .clk_pull_res   = MSDC_PULL_RES_23K,

    .rst_wp_pull_res= MSDC_PULL_RES_23K,

    .data_pins      = 4,

    .data_offset    = 0,

    .flags          = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_CD_PIN_EN,

};

这个相当于SD卡的私有数据。

来分析下mt6573_sd_probe(struct platform_device *pdev)

hw   = (struct mt6573_sd_host_hw*)pdev->dev.platform_data; //这个函数相当于hw =mt6573_sd0_hw 红色字体的变量是等价的

    reg  = platform_get_resource(pdev, IORESOURCE_MEM, 0);       //申请驱动的内存

    dma  = platform_get_resource(pdev, IORESOURCE_DMA, 0);     //申请驱动的DMA空间

    irq  = platform_get_irq(pdev, 0);                                                            //中断申请

    cirq = platform_get_irq(pdev, 1);                                                           //插卡外部中断申请

    mmc->ops        = &mt6573_sd_ops;                                                      //SD卡的处理函数,这个也是重点,等下再进入分析 www.2cto.com

    mmc->f_min      = HOST_MIN_SCLK;

    mmc->f_max      = HOST_MAX_SCLK;                                                //SD卡的工作时钟

    ................

    tasklet_init(&host->card_tasklet, mt6573_sd_tasklet_card, (ulong)host);

    tasklet_init(&host->fifo_tasklet, mt6573_sd_tasklet_fifo, (ulong)host);

    tasklet_init(&host->dma_tasklet, mt6573_sd_tasklet_dma, (ulong)host);

    这三个函数是中断处理下半部分别是处理识别卡/卡传输数据的buffer/卡传输数据的DMA通道。

    mt6573_sd_init_hw(host, dma);                                                        //具体SD卡的硬件寄存器参数的设置

        if (hw->flags & MSDC_CD_PIN_EN) {

        if (hw->request_cd_eirq) {                   

            hw->request_cd_eirq(mt6573_sd_cd_eirq, (void*)host);

        } else {

            mt65xx_irq_set_sens(cirq, MT65xx_EDGE_SENSITIVE);

            ret = request_irq((unsigned int)cirq, (irq_handler_t)mt6573_sd_cd_irq, 0, DRV_NAME, host);

            if (ret)

                goto free_irq;

        }

    }

    这一段是热插拔识别SD卡的重要函数,做热插拔这里必须实现。

    platform_set_drvdata(pdev, mmc);                      //把mmc的数据挂到pdev私有数据下

    ret = mmc_add_host(mmc);                                  //把mmc加载到主控制器队列里面去

    ret = misc_register(&msdc_em_dev[host->id]);    //建立SD卡的另外ops的设置,等下也做分析

    static struct miscdevice msdc_em_dev[] = {

    {

        .minor    = MISC_DYNAMIC_MINOR,

        .name    = "mt6573-sd0",

        .fops    = &msdc_em_fops,

    },

    从中可以看出主要是为了处理msdc_em_fops,点进去,

    static struct file_operations msdc_em_fops = {

    .owner        = THIS_MODULE,

    .unlocked_ioctl    = mt6573_sd_ioctl,

    .open        = mt6573_sd_open,

    };

    即分别实现了ioctl 和 open。

 

    刚说要分析mt6573_sd_ops,点进去看,

     static struct mmc_host_ops mt6573_sd_ops = {

    .request         = mt6573_sd_request,                                     //SD卡实现通信的请求,这个函数很重要,等下再分析

    .set_ios         = mt6573_sd_set_ios,                                      //SD卡的时钟,电压,数据通道等设置  

    .get_ro          = mt6573_sd_card_readonly,                         //实现SD卡的只读形式

    .get_cd          = mt6573_sd_card_inserted,                         //实现SD卡插入函数

    .enable_sdio_irq = mt6573_sd_enable_sdio_irq,            //SD卡中断的使能

};

    即分别实现了上述各函数。

重点来看看函数:

static void mt6573_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)

{

     struct mt6573_sd_host *host = mmc_priv(mmc);            //host为mmc的私有值

      if (!is_card_present(host) || host->power_mode == MMC_POWER_OFF) {

     ..........

    }                                    //判断又没SD卡插入以及SD电源开了没

    if ((host->id ==0) || (host->id == 1)) {

        MSG(OPS, "Enable SD host/card working ability!\n");

        clr_device_working_ability(clock_id[host->id], SLOW_IDLE_STATE);

        clr_device_working_ability(clock_id[host->id], DEEP_IDLE_STATE);

    }                                    //设置host时钟,card的时钟保持工作状态

       msdc_set_bksz(data->blksz);                  //设置SD卡的block数据大小

       msdc_clr_fifo();                                           //传输之前先清空fifo缓冲区的数据

      if (dma) {                //判断用DMA方式还是FIFO方式来传输数据

            msdc_dma_on();

            msdc_fifo_irq_off();

        } else {

            msdc_dma_off();

            msdc_fifo_irq_on();

         }

         if (mt6573_sd_send_command(host, cmd, polling, CMD_TIMEOUT) != 0)

         这个函数是向SD卡发送指令,进入这个函数是一系列SD卡的指令分类处理,具体参照SD的手册看这部分代码,我个人就没怎么仔细研究啦。

         if (cmd->opcode == SD_IO_RW_EXTENDED) {

            if (cmd->arg & 0x08000000) {

                /* SDIO workaround for CMD53 multiple block transfer */

                if (data->blocks > 1) {

                    struct mmc_command abort;

                    memset(&abort, 0, sizeof(struct mmc_command));

                    abort.opcode = SD_IO_RW_DIRECT;

                    abort.arg    = 0x80000000;            /* write */

                    abort.arg   |= 0 << 28;               /* function 0 */

                    abort.arg   |= SDIO_CCCR_ABORT << 9;  /* address */

                    abort.arg   |= 0;                     /* abort function 0 */

                    abort.flags  = (unsigned int)-1;

                    (void)mt6573_sd_send_command(host, &abort, 1, CMD_TIMEOUT);

                }

            } else {

                /* SDIO workaround for CMD53 multiple byte transfer, which

                 * is not 4 byte-alignment

                 */

                if (data->blksz % 4) {

                    /* The delay is required and tunable. The delay time must

                     * be not too small. Currently, it is tuned to 25us.(CHECKME)

                     */

                    udelay(25);

                    msdc_reset();

                }

            }

            这一段主要是读写的函数了,是否工作在cmd53模式下。

            这样整个request函数分析完了,整体感觉就是先设置SD参数,然后向SD发指令,等待SD应答。应答后以何种方式来传送数据,数据是怎样传送滴。等等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: