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

linux内核中的MFD子系统的更多相关文章

  1. Linux内核中SPI/I2c子系统剖析

    Linux内核中,SPI和I2C两个子系统的软件架构是一致的,且Linux内核的驱动模型都以bus,driver,device三种抽象对象为基本元素构建起来.下文的分析将主要用这三种抽象对象的创建过程 ...

  2. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  3. Linux内核中的GPIO系统之(3):pin controller driver代码分析

    一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...

  4. [转] Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  5. 【内核】探究linux内核,超详细解析子系统

    Perface 前面已经写过一篇<嵌入式linux内核的五个子系统>,概括性比较强,也比较简略,现在对其进行补充说明. 仅留此笔记,待日后查看及补充! Linux内核的子系统 内核是操作系 ...

  6. linux内核中socket的创建过程源码分析(总结性质)

    在漫长地分析完socket的创建源码后,发现一片浆糊,所以特此总结,我的博客中同时有另外一篇详细的源码分析,内核版本为3.9,建议在阅读本文后若还有兴趣再去看另外一篇博文.绝对不要单独看另外一篇. 一 ...

  7. Linux内核中的GPIO系统之(3):pin controller driver代码分析--devm_kzalloc使用【转】

    转自:http://www.wowotech.net/linux_kenrel/pin-controller-driver.html 一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道 ...

  8. Linux内核驱动之GPIO子系统API接口概述

    1.前言 在嵌入式Linux开发中,对嵌入式SoC中的GPIO进行控制非常重要,Linux内核中提供了GPIO子系统,驱动开发者在驱动代码中使用GPIO子系统提供的API函数,便可以达到对GPIO控制 ...

  9. TCP/IP协议栈在Linux内核中的运行时序分析

    网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...

随机推荐

  1. 第五章、Django之模型层---单表操作

    目录 第五章.Django之模型层---单表操作 一.ORM查询 二.Django测试环境搭建 三.单表查询 1. 增 2. 改 3. 删 4. 查 第五章.Django之模型层---单表操作 一.O ...

  2. 在VS2017添加MVC项目

    以前一直是用vs2012 MVC直接可以找到 在公司用的是vs2017  今天想创建一个MVC,和vs不同啊!!! 居然找不到MVC  然后找找找  ,突然想到创建asp.net 项目的时候发现了MV ...

  3. web开发:动画及阴影

    一.小米拼接 二.过渡动画 三.过度案例 四.盒子阴影 五.伪类设计边框 一.小米拼接 将区域整体划分起名 => 对其他区域布局不产生影响提出公共css => reset操作当有区域发送显 ...

  4. 关于单例模式getInstance()的使用

    /**  * 对象的实例化方法,也是比较多的,最常用的方法是直接使用new,而这是最普通的,如果要考虑到其它的需要,如单实例模式,层次间调用等等. * 直接使用new就不可以实现好的设计好,这时候需要 ...

  5. PAT Basic 1049 数列的片段和 (20 分)

    给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段.例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) ...

  6. java—锁的学习研究

    摘抄自博客:https://www.cnblogs.com/qifengshi/p/6831055.html 标题:Java中的锁分类 锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/ ...

  7. 原生js中如果有多个onload事件解决方案

    在一个页面中有两个JavaScript 分别都用到了window.onload 一个是:window.onload=func1,另一个是:window.onload=func2 这样就造成了一个Jav ...

  8. Canvas对画布及文字控制基础API学习

    这次纯API练习,比较简单,但是是为了之后的结合项目打基础的,所以也不能忽视它,下面开始: Canvas的平移.旋转.缩放 这里还是以上次画那个青春痘的DEMO为例[http://www.cnblog ...

  9. java学习笔记12-继承

    继承就是子类继承父类的特征和行为 有时候单一划分某个类别并不能处理所有情况,某些类别下有明显不同的子类,这些子类虽然拥有类似的行为和属性,但是他们各自发生的这些行为的方式或者属性对某些结果的影响是不一 ...

  10. faucet搭建(linux/win)

    sudo apt-get install libssl-dev pip3 install flaskpip3 install flask_scriptpip3 install flask_sqlalc ...