zoukankan      html  css  js  c++  java
  • sdio 框架分析<1>

    SDIO的master board info:
    ---------------------------------------------------------------------------------------------------------
    #define SD0_DETECT_GPIO        101
    //驱动器所占资源【host寄存器所占用的AP地址,及大小,探测GPIO/中断等】
    static struct resource sprd_sdio_resource[][3] = {
           SDIO_RESOURCE_BUILDER(SPRD_SDIO0_BASE, SPRD_SDIO0_SIZE, SD0_DETECT_GPIO, IRQ_SDIO0_INT),/*sdio0*/
     };

    //相关Pin配置,初始化SDIO的PIN状态
    static unsigned long sdio_func_cfg[] __initdata = {
            MFP_CFG_X(SD0_CLK, AF0, DS3, F_PULL_NONE, S_PULL_NONE, IO_Z),
            MFP_CFG_X(SD_CMD, AF0, DS1, F_PULL_UP,  S_PULL_NONE, IO_Z),
            MFP_CFG_X(SD_D0, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
            MFP_CFG_X(SD_D1, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
            MFP_CFG_X(SD_D2, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
            MFP_CFG_X(SD_D3, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
    };
    static unsigned long sdcard_detect_gpio_cfg = MFP_CFG_X(RFCTL11, AF3, DS1, F_PULL_UP,S_PULL_NONE, IO_Z);
    static void sprd_config_sdio_pins(void)
    {
            sprd_mfp_config(sdio_func_cfg, ARRAY_SIZE(sdio_func_cfg));
            sprd_mfp_config(&sdcard_detect_gpio_cfg, 1);
    }
    //platform device声明
    #define SDIO_DEV_BUILDER(bus_id, res)          \
           {       \
                   .name           = "sprd-sdhci", \
                   .id     = (bus_id),     \
                   .num_resources  = ARRAY_SIZE(res),      \
                   .resource       = (res),        \
           }

    struct platform_device sprd_sdio_device[] = {
           SDIO_DEV_BUILDER(0, sprd_sdio_resource[0]),
     };

    //启用AHB,注册platfrom device到系统中
    void __init sprd_add_sdio0_device(void)
    {
            int err;
            /* Enable SDIO0 Module */
            __raw_bits_or(BIT_4, AHB_CTL0);
            /* reset sdio0 module*/
            __raw_bits_or(BIT_12, AHB_SOFT_RST);
            __raw_bits_and(~BIT_12, AHB_SOFT_RST);
            platform_device_register(&sprd_sdio_device[0]);
    }

    SDIO master platform drvier:
    -------------------------------------------------------------------------------------------------------------
    static struct platform_driver sdhci_sprd_driver = {
        .probe        = sdhci_sprd_probe,
        .remove        = __devexit_p(sdhci_sprd_remove),
        .suspend    = sdhci_sprd_suspend,
        .resume            = sdhci_sprd_resume,
        .driver        = {
            .owner    = THIS_MODULE,
            .name    = "sprd-sdhci",
        },
    };
    注册驱动到系统:
    static int __init sdhci_sprd_init(void)
    {
        return platform_driver_register(&sdhci_sprd_driver);
    }
    匹配过程如SPI,不再详细叙述。
    sdhci_sprd_driver的probe函数中具体做的事情如SPI:
    逻辑与SPI基本相同,只是master由spi_master换成了sdhci_host【sdhci_alloc_host】,
    最后通过sdhci_add_host(host),添加到MMC系统中,此时dev与host已经完成了挂接的操作
    在此其中将sdhci_host转换成mmc结构,并添加到系统中:mmc_add_host(mmc);

    这里我们着重分析加入MMC子系统的详细过程:sdhci_add_host(struct sdhci_host *host)
    此函数的主要功能为,转换sdhci_host结构体到mmc_host内核标准结构体,并挂接上相关标准函数,加入MMC子系统中

    1. 设置MMC操作接口:mmc->ops = &sdhci_ops; 【后面需要详解】  
    2. 添加两个tasklet并启动计时器:
    tasklet_init(&host->card_tasklet, sdhci_tasklet_card, (unsigned long)host);【用于MMC插槽上的状态变化】
    tasklet_init(&host->finish_tasklet, sdhci_tasklet_finish, (unsigned long)host);【用于命令传输完成后的处理】
    setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);【用于等待硬件中断】
    3. 中断映射:
    ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, mmc_hostname(mmc), host);【中断处理】
    4. 初始化MMC设备,包括复位控制器:
    sdhci_init(host, 0);
    5. 加入MMC子系统:
    mmc_add_host(mmc);
    6. 使能设备探测功能:
    sdhci_enable_card_detection(host);

    在步骤5中最重要的操作是:
    void mmc_start_host(struct mmc_host *host)
    {
        host->f_init = max(freqs[0], host->f_min);        //获取初始频率
        host->rescan_disable = 0;                        //使能探测
        mmc_power_up(host);                                //上电
        mmc_detect_change(host, 0);                        //延迟0,直接调用host->detect进行设备探测
    }
    这个detect域在分配sdhc_host中的mmc_host时被初始化,INIT_DELAYED_WORK(&host->detect, mmc_rescan);
    这里相当于一上电后,立刻进行扫描操作.

    扫描操作在下面会详细描述,这里来简述扫描完成后的设备匹配工作:
    当扫描到对应的设备时,会分配对应的func,根据协议寄存器初始化相关数据域后,并挂在对应的sdio_bus_type总线上:
    mmc_attach_sdio---->sdio_init_func----> sdio_alloc_func ----> func->dev.bus = &sdio_bus_type;
    当sdio func驱动加载时,也直接挂在sdio总线上,并注册到系统中【关键点】:
    sdio_register_driver----> drv->drv.bus = &sdio_bus_type
    这个时候总线优先调用match函数进行匹配, bus.probe与driver.probe选其一,在sdio bus的probe中,已经包含了driver.probe.

    其它两种设备:sd与mmc都对应与mmc_bus_type,
    在注册块设备时调用:mmc_register_driver---->drv->drv.bus = &mmc_bus_type;
    这样也完成了对应的probe流程。
    注:在sdio_bus中match做的是匹配vendor/device id,而在mmc_bus中的match做的是直接返回1,probe也是直接调用driver的probe,故后者的匹配工作
    完全在mmc设备驱动这一端.
    static int mmc_blk_probe(struct mmc_card *card)
    {
        struct mmc_blk_data *md, *part_md;
        char cap_str[10];

        md = mmc_blk_alloc(card);

        string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str));

        mmc_blk_alloc_parts(card, md);

        mmc_set_drvdata(card, md);
        mmc_fixup_device(card, blk_fixups);

        mmc_add_disk(md);

        list_for_each_entry(part_md, &md->part, part) {
            if (mmc_add_disk(part_md))
                goto out;
        }
        return 0;
    }
    为每一个mmc设备都独立建一个管理结构提并置于card device的driver data中.


    这里来总结下,mmc的几个ops域:

    sdhci_host->ops【sdhci_ops】:主要是相关的sdio主控制器的参数:由mmc驱动来实现
        void    (*set_clock)(struct sdhci_host *host, unsigned int clock);
        int        (*enable_dma)(struct sdhci_host *host);
        unsigned int    (*get_max_clock)(struct sdhci_host *host);
        unsigned int    (*get_min_clock)(struct sdhci_host *host);
        unsigned int    (*get_timeout_clock)(struct sdhci_host *host);
        int        (*platform_8bit_width)(struct sdhci_host *host, int width);
        void (*platform_send_init_74_clocks)(struct sdhci_host *host, u8 power_mode);
        unsigned int    (*get_ro)(struct sdhci_host *host);
        void    (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
        void    (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
        int    (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
        void    (*hw_reset)(struct sdhci_host *host);
        void    (*platform_suspend)(struct sdhci_host *host);
        void    (*platform_resume)(struct sdhci_host *host);
        void    (*platform_init)(struct sdhci_host *host);
    提供者: mmc master驱动

    mmc_host->ops 【mmc_host_ops】:这个域由mmc core来提供
        int (*enable)(struct mmc_host *host);
        int (*disable)(struct mmc_host *host);
        void    (*post_req)(struct mmc_host *host, struct mmc_request *req, int err);
        void    (*pre_req)(struct mmc_host *host, struct mmc_request *req,bool is_first_req);
        void    (*request)(struct mmc_host *host, struct mmc_request *req);
        void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
        int    (*get_ro)(struct mmc_host *host);
        int    (*get_cd)(struct mmc_host *host);
        void    (*enable_sdio_irq)(struct mmc_host *host, int enable);
        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
        int    (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
        int    (*execute_tuning)(struct mmc_host *host, u32 opcode);
        void    (*enable_preset_value)(struct mmc_host *host, bool enable);
        int    (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
        void    (*hw_reset)(struct mmc_host *host);

    提供者:
    static const struct mmc_host_ops sdhci_ops = {
        .request    = sdhci_request,
        .set_ios    = sdhci_set_ios,
        .get_ro        = sdhci_get_ro,
        .hw_reset    = sdhci_hw_reset,
        .enable_sdio_irq = sdhci_enable_sdio_irq,
        .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
        .execute_tuning            = sdhci_execute_tuning,
        .enable_preset_value        = sdhci_enable_preset_value,
    };

    mmc_host->bus_ops 【mmc_bus_ops】:
    struct mmc_bus_ops {
        int (*awake)(struct mmc_host *);
        int (*sleep)(struct mmc_host *);
        void (*remove)(struct mmc_host *);
        void (*detect)(struct mmc_host *);
        int (*suspend)(struct mmc_host *);
        int (*resume)(struct mmc_host *);
        int (*power_save)(struct mmc_host *);
        int (*power_restore)(struct mmc_host *);
        int (*alive)(struct mmc_host *);
    };
    提供者:主要针对相关的设备
    SDIO:
    static const struct mmc_bus_ops mmc_sdio_ops = {
        .remove = mmc_sdio_remove,
        .detect = mmc_sdio_detect,
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
        .power_restore = mmc_sdio_power_restore,
        .alive = mmc_sdio_alive,
    };
    SD:
    static const struct mmc_bus_ops mmc_sd_ops = {
        .remove = mmc_sd_remove,
        .detect = mmc_sd_detect,
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_sd_power_restore,
        .alive = mmc_sd_alive,
    };
    MMC:
    static const struct mmc_bus_ops mmc_ops = {
        .awake = mmc_awake,
        .sleep = mmc_sleep,
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_power_restore,
        .alive = mmc_alive,
    };

  • 相关阅读:
    android cts 命令的说明
    k8s认证授权和dashboard部署
    Pod对象的基本概念
    k8s创建自定义资源
    flannel网络插件介绍
    go语言包的介绍
    安装k8s的自动代码生成器
    k8s的pv和pvc概念
    Es索引匹配查询
    shell实现自动化部署项目
  • 原文地址:https://www.cnblogs.com/wenhuisun/p/3092655.html
Copyright © 2011-2022 走看看