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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM