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

      

      

            

      

    

    

    

  

    

  

  

参考资料:

  MFD subsystem

猜你喜欢

转载自www.cnblogs.com/dakewei/p/10991941.html