zoukankan      html  css  js  c++  java
  • linux内核中的MFD子系统

    分析用的内核版本为5.1.3

    1.MFD全称

      Multi-function Device,多功能设备

    2. 为何会出现MFD子系统

      由于出现了一类具有多种功能的外围设备或cpu内部集成的硬件模块

    3. 有哪些多功能设备呢?

      3.1 PMIC,电源管理芯片

        da9063: 调节器,led控制器,看门狗,实时时钟控制器,温度传感器,震动马达驱动,长按关机功能(ON key)

        max77843: 调节器,充电器,燃油量表,触觉反馈,led控制器,micro USB接口控制器

        wm831x: 调节器,时钟,实时时钟控制器,看门狗,触摸控制器,温度传感器,背光控制器,状态led控制器,GPIO,长按关机功能(ON key),ADC

        其它: 甚至具有codec功能

      3.2 atmel-hlcdc: 显示控制器和背光pwm

      3.3 Diolan DLN2: USB转I2C,SPI和GPIO控制器

      3.4 Realtek PCI-E读卡器: SD/MMC和记忆棒读取器

    4. MFD子系统解决的主要问题

      在不同的内核子系统中注册这些驱动。特别是外部外围设备仅仅由一个结构体struct device(或是指定的i2c_client或spi_device)呈现

    5. MFD子系统的优点有哪些?

      5.1 允许在多个子系统中注册相同的设备

      5.2 MFD驱动必须能否复用总线(主要是关于锁的处理)和处理中断请求

      5.3 处理时钟

      5.4 需要配置IP

      5.5 允许驱动重用,多个多功能设备能重用其它子系统中的驱动

    6. MFD提供的API

      

    int mfd_add_devices(struct device *parent,int id,
                        const struct mfd_cell *cells, int n_devs,
    struct resource *mem_base, int irq_base, struct irq_domain *irq_domain);
    extern void mfd_remove_devices(struct device *parent);

    这些接口定义在include/linux/mfd/core.h中,在drivers/mfd/mtd-core.c中被实现

    7. MFD提供的结构体

    struct mfd_cell {
        const char      *name;
        int         id;
    
        /* refcounting for multiple drivers to use a single cell */
        atomic_t        *usage_count;
        int         (*enable)(struct platform_device *dev);
        int         (*disable)(struct platform_device *dev);
    
        int         (*suspend)(struct platform_device *dev);
        int         (*resume)(struct platform_device *dev);
    
        /* platform data passed to the sub devices drivers */
        void            *platform_data;
        size_t          pdata_size;
    
        /* device properties passed to the sub devices drivers */
        struct property_entry *properties;
    
        /*  
         * Device Tree compatible string
         * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details
         */
        const char      *of_compatible;
    
        /* Matches ACPI */
        const struct mfd_cell_acpi_match    *acpi_match;
    
        /*  
         * These resources can be specified relative to the parent device.
         * For accessing hardware you should use resources from the platform dev
         */
        int         num_resources;
        const struct resource   *resources;
    
        /* don't check for resource conflicts */
        bool            ignore_resource_conflicts;
    
        /*  
         * Disable runtime PM callbacks for this subdevice - see
         * pm_runtime_no_callbacks().
         */
        bool            pm_runtime_no_callbacks;
    
        /* A list of regulator supplies that should be mapped to the MFD
         * device rather than the child device when requested
         */
        const char * const  *parent_supplies;
        int         num_parent_supplies;
    };

    8. 示例分析

     8.1 分析tps6507x的多功能驱动

      8.1.1 涉及的文件

        drivers/mfd/tps6507x.c

        include/linux/mfd/tps6507x.h

        drivers/regulator/tps6507x-regulator.c

        drivers/input/touchscreen/tps6507x-ts.c

      8.1.2 涉及的结构体

    static const struct mfd_cell tps6507x_devs[] = { 
        {   
            .name = "tps6507x-pmic",
        },  
        {   
            .name = "tps6507x-ts",
        },  
    };

        从以上结构体可以得出,tps6507x系列芯片提供两种功能: 电源管理功能(regulator)+触摸屏功能(touchscreen)

        

        

    static struct i2c_driver tps6507x_i2c_driver = {
        .driver = {
               .name = "tps6507x",
               .of_match_table = of_match_ptr(tps6507x_of_match),
        },
        .probe = tps6507x_i2c_probe,
        .id_table = tps6507x_i2c_id,
    };

        这个结构体为tps6507x提供探测函数tps6507x_i2c_probe

        

    struct tps6507x_dev {
        struct device *dev;
        struct i2c_client *i2c_client;
        int (*read_dev)(struct tps6507x_dev *tps6507x, char reg, int size,
                void *dest);
        int (*write_dev)(struct tps6507x_dev *tps6507x, char reg, int size,
                 void *src);
    
        /* Client devices */
        struct tps6507x_pmic *pmic;
    };

        tps6507x 的读写接口就是放在这个结构体中,这也就是所谓的共性

      

      8.1.3 对tps6507x进行初始化

        subsys_initcall(tps6507x_i2c_init);

        调用路径如下:

            tps6507x_i2c_init->i2c_add_driver

      8.1.4 探测函数tps6507x_i2c_probe做了些什么?

        注册tps6507x的读写函数: tps6507x_i2c_read_device和tps6507x_i2c_write_device到结构体struct tps6507x_dev中

        

      8.1.5 tps6507x的两种功能实现在哪里呢?

        drivers/regulator/tps6507x-regulator.c,这里面实现电源管理功能(电压调节器驱动)

        drivers/input/touchscreen/tps6507x-ts.c,这里面实现触摸屏功能

      8.1.6 tps6507x电压调节器驱动

        8.1.6.1 调用路径

        subsys_initcall(tps6507x_pmic_init);

          tps6507x_pmic_init->platform_driver_register

        8.1.6.2 探测函数tps6507x_pmic_probe干了些什么?

          获取共用的结构体struct tps6507x_dev

          再注册相关的结构体以便提供pmic的相关操作接口,如下:       

                  static struct regulator_ops tps6507x_pmic_ops = { 
                      .is_enabled = tps6507x_pmic_is_enabled, 检查tps6507x的pmic功能是否已经使能了
                      .enable = tps6507x_pmic_enable, 使能tps6507x的pmic功能
                      .disable = tps6507x_pmic_disable, 禁用tsp6507x的pmic功能
                      .get_voltage_sel = tps6507x_pmic_get_voltage_sel, 获取电压值
                      .set_voltage_sel = tps6507x_pmic_set_voltage_sel, 设置电压值
                      .list_voltage = regulator_list_voltage_table, 列出电压表
                      .map_voltage = regulator_map_voltage_ascend,
                  };

      

      8.1.7 tps6507x触摸屏驱动

        8.1.7.1 驱动在哪里?

          drivers/input/touchscreen/tps6507x-ts.c

        8.1.7.2 分析probe函数都做了些什么?

          获取公用的结构体struct tps6507x_dev

          填充结构体struct tps6507x_ts,关键是注册了函数tps6507x_ts_poll

          

     8.2 分析da9063相关驱动

      8.2.1 mfd驱动

        8.2.1.1 相关源码

          drivers/mfd/da9063-i2c.c

        8.2.1.2 分析探测函数da9063_i2c_probe的调用路径

          da9063_i2c_probe->da9063_device_init

        8.2.1.3 da9063_device_init做了些什么?

          读取da9063的芯片ID,检查是否匹配

          读取da9063的variant ID,不同的variant ID表示不同的封装

          通过接口devm_mfd_add_devices添加具体的结构体struct mfd_cell数组,这个数组里包含了多个驱动相关的信息,如名字,资源等

        8.2.1.4 结构体数组da906_common_devs     

    static const struct mfd_cell da9063_common_devs[] = { 
        {   
            .name       = DA9063_DRVNAME_REGULATORS,
            .num_resources  = ARRAY_SIZE(da9063_regulators_resources),
            .resources  = da9063_regulators_resources,
        },  
        {   
            .name       = DA9063_DRVNAME_LEDS,
        },  
        {   
            .name       = DA9063_DRVNAME_WATCHDOG,
            .of_compatible  = "dlg,da9063-watchdog",
        },  
        {   
            .name       = DA9063_DRVNAME_HWMON,
            .num_resources  = ARRAY_SIZE(da9063_hwmon_resources),
            .resources  = da9063_hwmon_resources,
        },  
        {   
            .name       = DA9063_DRVNAME_ONKEY,
            .num_resources  = ARRAY_SIZE(da9063_onkey_resources),
            .resources  = da9063_onkey_resources,
            .of_compatible = "dlg,da9063-onkey",
        },  
        {
            .name       = DA9063_DRVNAME_VIBRATION,
        },
    };

          这个结构体数组中就包含了调节器,led控制器,看门狗,硬件监测(电压监测,温度监测),长按关键功能(onkey),震动等驱动名称,也就是da9063会关联(具有)这些功能,da9063有两种硬件版本,一种为DA9063,另一种为DA9063L,这两种硬件的差异在于DA9063具有实时时钟功能,而后者没有此功能

        8.2.1.5 结构体数组da9063_devs      

    /* Only present on DA9063 , not on DA9063L */
    static const struct mfd_cell da9063_devs[] = {
        {
            .name       = DA9063_DRVNAME_RTC,
            .num_resources  = ARRAY_SIZE(da9063_rtc_resources),
            .resources  = da9063_rtc_resources,
            .of_compatible  = "dlg,da9063-rtc",
        },
    };

        8.2.1.6 da9063_common_devsda9063_devs中的这些具体的驱动实现在哪里?

            drivers/regulator/da9063-regulator.c (调节器驱动)

            (没有找到da9063的led控制器驱动)

            drivers/watchdog/da9063_wdt.c (看门狗驱动)

            (没有找到da9063的硬件监测驱动)

            drivers/input/misc/da9063_onkey.c (onkey驱动)

            (没有找到da9063的震动功能驱动)

            drivers/rtc/rtc-da9063.c (实时时钟驱动)

     

        8.2.1.7 重要的结构体struct da9063    

    struct da9063 {
        /* Device */
        struct device   *dev;
        enum da9063_type type;
        unsigned char   variant_code;
        unsigned int    flags;
    
        /* Control interface */
        struct regmap   *regmap;
    
        /* Interrupts */
        int     chip_irq;
        unsigned int    irq_base;
        struct regmap_irq_chip_data *regmap_irq;
    };

        

          

          

          

            

                

          

        

        

        

      

        

      

      

    参考资料:

      MFD subsystem

  • 相关阅读:
    简单对称加密
    temp
    标点符号
    PHP定时执行计划任务
    从杨致远辞去雅虎说起,那些衰落的网站巨头给我们的启示
    JS判断手机浏览器
    如何制作在线参考手册
    不是每个程序员都是适合创业,即使你工作了十年
    两级导航栏联动效果
    关于腾讯ip接口一个流传很广的错误用法
  • 原文地址:https://www.cnblogs.com/dakewei/p/10991941.html
Copyright © 2011-2022 走看看