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

    转自:https://www.cnblogs.com/dakewei/p/10991941.html

    分析用的内核版本为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_devs和da9063_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

  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/12746329.html
Copyright © 2011-2022 走看看