首页 > 系统相关 >以PMIC为例简析Linux MFD/Remap/Regulator的使用

以PMIC为例简析Linux MFD/Remap/Regulator的使用

时间:2023-10-15 11:44:23浏览次数:42  
标签:Remap MFD struct int irq regulator 简析 regmap

 关键词:ADI、SPI、Regmap、MFD、Regulator、PMIC等等。

 以SC27XX为例,梳理一个PMIC用到的内核模块。

1. MFD框架

MFD是Multi-Function Device,MFD子系统是Linux下一种用于管理和控制多功能设备的软件框架。他提供一种统一接口,使得多个设备可以通过一个驱动程序进行管理和控制。

Kernel使能MFD:

Device Drivers
    ->Multifunction device drivers

MFD是多个具有类似功能设备的集合,每一个功能称为一个cell。MFD为每个cell创建一个platform设备。

整个MFD包括3部分:

  • MFD Core提供MFD设备的注册去注册,以及对Cell的操作。
  • MFD设备驱动。
  • MFD Cell描述符,一个描述符对应一个MFD设备单元。MFD为每个Cell创建一个Platform设备。

MFD主要功能包括:

  • MFD对所属设备进行统一关键,包括使能和去使能,以及suspend/resume。
  • MFD进行统一中断处理。
  • MFD负责设备注册和注销。

MFD常用于PMIC设备。

1.1 MFD Core

MFD Core设备注册和去注册API如下:

extern 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);

static inline int mfd_add_hotplug_devices(struct device *parent,
        const struct mfd_cell *cells, int n_devs)
{
    return mfd_add_devices(parent, PLATFORM_DEVID_AUTO, cells, n_devs,
            NULL, 0, NULL);
}

extern void mfd_remove_devices(struct device *parent);

extern int devm_mfd_add_devices(struct device *dev, int id,
                const struct mfd_cell *cells, int n_devs,
                struct resource *mem_base,
                int irq_base, struct irq_domain *irq_domain);

mfd_add_devices()注册一个MFD主设备,devm_mfd_add_devices是带设备资源管理的API变种。

mfd_remove_devices()是将一个MFD去注册接口。

parent:MFD主设备,后面Cell创建的设备挂载在下面。

id:表示后续创建Cell Platform设备时ID如何创建,包括PLATFORM_DEVID_NONE和PLATFORM_DEVID_AUTO两种方式。

cells:struct mfd_cell结构体数组,每一个成员表示一个Cell。

n_devs:Cell数量。

mem_base:内存地址基准。

irq_base:irq号基准。

irq_domain:当前MFD设备的struct irq_domain。

关于Cell的操作:

extern int mfd_cell_enable(struct platform_device *pdev);--调用Cell的enable回调函数。
extern int mfd_cell_disable(struct platform_device *pdev);--调用Cell的disable回调函数。
extern int mfd_clone_cell(const char *cell, const char **clones,
        size_t n_clones);--一个Cell被多个驱动使用,创建一系列别名。
static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
{
    return pdev->mfd_cell;
}

MFD中使用struct mfd_cell表示:

struct mfd_cell {
    const char        *name;--名称。
    int            id;--Cell ID号。
    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);
    void            *platform_data;--平台私有数据指针。
    size_t            pdata_size;
    struct property_entry *properties;
    const char        *of_compatible;--和DTS中Device匹配关键词。
    const struct mfd_cell_acpi_match    *acpi_match;
    int            num_resources;
    const struct resource    *resources;
    bool            ignore_resource_conflicts;
    bool            pm_runtime_no_callbacks;
    const char * const    *parent_supplies;
    int            num_parent_supplies;
};

2 Regmap框架

对于I2C/SPI类型的外设,对其进行读写有很多重复逻辑。Linux引入Regmap模型,Regmap将寄存器访问共同逻辑抽象出来,只需关注寄存器和值,屏蔽接口差异。

Regmap提供统一接口函数来访问外设寄存器,减少I2C/SPI等外设驱动开发难度。

Regmap在驱动和硬件之间加了一层cache,降低了低俗IO操作次数,提高了访问效率,但是降低了实时性。

Regmap可以分为3层:

Regmap Core:提供Regmap API接口,实现Regmap机制。包括regmap.c。

regcache:提供Regmap API和底层物理总线之间的Cache层,包括flat、rbtree、lzo共3中方式。包括regcache.c、regcache-flag.c、regcache-lzo.c、regcache-rbtree.c。

底层总线接口:执行数据读写的底层物理总线封装,包括I2C、SPI、IRQ等等。包括regmap-spi.c、regmap-irq.c等。

另外regmap debugfs在/sys/kernel/debug/regmap下提供对regmap的调试接口。

 2.1 Regmap数据结构

struct regmap_bus是底层物理总线接口接入到Regmap框架结构体。一个struct regmap_bus表示一个底层物理总线接口,在注册时调用。

struct regmap_bus {
    bool fast_io;
    regmap_hw_write write;--写一定大小数据到外设。
    regmap_hw_gather_write gather_write;
    regmap_hw_async_write async_write;
    regmap_hw_reg_write reg_write;--写值到单个寄存器。
    regmap_hw_reg_update_bits reg_update_bits;
    regmap_hw_read read;--读一定大小数据到buffer。
    regmap_hw_reg_read reg_read;--从单个寄存器读取值。
    regmap_hw_free_context free_context;
    regmap_hw_async_alloc async_alloc;
    u8 read_flag_mask;
    enum regmap_endian reg_format_endian_default;--寄存器地址大小端设置。
    enum regmap_endian val_format_endian_default;--寄存器值大小端设置。
    size_t max_raw_read;
    size_t max_raw_write;
};

struct regmap_bus是描述物理总线在Regmap中的特性。

struct regmap_config {
    const char *name;

    int reg_bits;--寄存器地址位宽。
    int reg_stride;--寄存器地址步进。
    int pad_bits;
    int val_bits;--寄存器数据位宽。
...
    bool disable_locking;
    regmap_lock lock;
    regmap_unlock unlock;
    void *lock_arg;

    int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
    int (*reg_write)(void *context, unsigned int reg, unsigned int val);

    bool fast_io;

    unsigned int max_register;--寄存器地址最大值。
...
};

2.2 Regmap接口函数

regmap_init是Regmap的注册接口函数,可以适配各种总线接口。regmap_init_i2c以及类似函数,是注册特定总线接口到Regmap的函数。

devm_开头的注册函数是带Device资源管理接口。

regmap_init(dev, bus, bus_context, config)
regmap_init_i2c(i2c, config)
...
devm_regmap_init(dev, bus, bus_context, config)
devm_regmap_init_i2c(i2c, config)

regmap_exit()是Regmap的注销函数。

regmap_read()/regmap_write()是Regmap读写函数。

其中map是Regmap注册返回的strcut regmap结构体,在Regmap内部表示一个已经注册的Regmap。

int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)

2.3 Regmap IRQ

struct regmap_irq_chip用于描述Regmap下一个irq_chip。

通过regmap_add_irq_chip()将struct regmap_irq_chip加入到Regmap,返回strcut regmap_irq_chip_data,其中包括struct irq_domain。

int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
            int irq_base, const struct regmap_irq_chip *chip,
            struct regmap_irq_chip_data **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);

int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
                 int irq_flags, int irq_base,
                 const struct regmap_irq_chip *chip,
                 struct regmap_irq_chip_data **data);
void devm_regmap_del_irq_chip(struct device *dev, int irq,
                  struct regmap_irq_chip_data *data);

int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data);

3 Regulator框架

Regulator Driver将Regulator注册到Regulator框架,Regulator Consumer根据名称获取到Regulator。然后对Regulator进行开关或者电压设置。

 Regulator注册和注销接口:

struct regulator_dev *
regulator_register(const struct regulator_desc *regulator_desc,
           const struct regulator_config *config);
struct regulator_dev *
devm_regulator_register(struct device *dev,
            const struct regulator_desc *regulator_desc,
            const struct regulator_config *config);
void regulator_unregister(struct regulator_dev *rdev);
void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);

 Regulator获取和释放:

struct regulator *__must_check regulator_get(struct device *dev,
                         const char *id);
struct regulator *__must_check devm_regulator_get(struct device *dev,
                         const char *id);
void regulator_put(struct regulator *regulator);
void devm_regulator_put(struct regulator *regulator);

Regulator开关好和电压设置:

int __must_check regulator_enable(struct regulator *regulator);
int regulator_disable(struct regulator *regulator);
int regulator_force_disable(struct regulator *regulator);
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
int regulator_get_voltage(struct regulator *regulator);

关于Regulator更多参考:《Linux Regulator Framework(1)_概述 (wowotech.net)》《Linux Regulator Framework(2)_regulator driver (wowotech.net)》。

4 PMIC(SC27XX)驱动框架

SC27XX芯片框架如下:

SOC借用SPI框架处理和PMIC的ADI接口通信。

PMIC驱动注册MFD设备,为每个功能创建设备;并基于Regmap-SPI建立寄存器通信通道。

内核为每个LDO/DCDC创建Regulator设备,内核其他驱动通过通过Regulator接口进行开关和电压设置。

 4.1 ADI驱动

ADI驱动初始化:

  • 分配一个SPI Master,并注册。
  • 初始化ADI硬件接口。
sprd_adi_init
  ->sprd_adi_probe
    ->spi_alloc_master--SOC ADI作为SPI Master分配。
    ->spi_controller_get_devdata
    ->sprd_adi_hw_init--ADI接口初始化。
    ->sprd_adi_set_wdt_rst_mode
    ->devm_spi_register_controller--将分配的SPI Master注册到SPI Framework。
    ->register_restart_handler--注册一个系统Restart的回调函数到restart_handler_list。
sprd_adi_exit
  ->sprd_adi_remove
    ->unregister_restart_handler

 ADI初始化完成后,挂载在下面的设备就可以通过调用SPI读写函数进行寄存器设置。

4.2 PMIC驱动

PMIC驱动比较简单,首先基于ADI接口SPI总线注册到Regmap;然后将每个功能作为MFD Cell创建设备。

sprd_pmic_init
    ->sprd_pmic_probe
        ->devm_regmap_init--将基于ADI的SPI总线注册到Regmap框架。
        ->devm_regmap_add_irq_chip--将PMIC的irq注册到Regmap,给MFD使用。
        ->devm_mfd_add_devices--注册MFD Cell,创建Platform设备。
sprd_pmic_exit

4.3 Regulator驱动

Regulator驱动获取PMIC创建的struct regmap结构体,后续的寄存器读写都基于Regmap进行。并创建一系列debugfs用于调试。最后将PMIC Regulator注册Regulator框架中。

regu_driver_init
  ->sprd_regulator_probe
    ->dev_get_regmap--获取父设备的struct regmap。
    ->debugfs_create_dir--创建/sys/kernel/debug/regulator下的调试文件。
    ->regulator_register_dt--在当前设备树中找到regulators节点,遍历并注册下面的regulator。
      -->regulator_parse_dt-->解析单个regulator节点,将属性写入struct sprd_regulator_desc中。
      ->regulator_register-->struct regulator_desc是描述regulator结构体,struct regulator_config是对regulator配置。
      ->rdev_init_debugfs-->在debugfs下创建对regulator调试的节点。

4.4 Regulator使用

一个典型的Regulator使用如下:

  • 根据名称获取Regulator。
  • 使能Regulator。
  • 读取或者设置电压。
  • 关闭Regulator。
    st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");
    if (!IS_ERR(st->reg_vdd)) {
        ret = regulator_enable(st->reg_vdd);
        if (ret)
            return ret;

        ret = regulator_get_voltage(st->reg_vdd);
        if (ret < 0)
            goto error_disable_reg_pos;

        pos_voltage_uv = ret;
    }
    regulator_disable(st->reg_vdd);

 

标签:Remap,MFD,struct,int,irq,regulator,简析,regmap
From: https://www.cnblogs.com/arnoldlu/p/17761663.html

相关文章

  • XSS攻击简析
    什么是XSS攻击?XSS攻击又称为跨站脚本(CrossSiteScripting),XSS的重点不在于跨站点,而是在于脚本的执行。XSS是一种经常出现在Web应用程序中的计算机安全漏洞,是由于Web应用程序对用户的输入过滤不足而产生的,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。XSS攻击有......
  • 湖南软件测评公司简析:软件功能测试和非功能测试的联系和区别
    一、软件功能测试软件功能测试旨在验证软件是否按照需求规格说明书的要求正常工作。具体而言,功能测试会对软件的所有功能进行测试,以确保其满足用户的需求和预期。在进行功能测试时,根据需求规格说明书编写测试用例,并在测试环境中逐一验证每个功能是否正常工作。通过功能测试......
  • 软件测评中心测试项目及测试过程简析,CMA、CNAS软件测试报告获取
    软件测试是产品周期中必不可少的一步,可以更好的保障软件质量,那么我们所知的软件测评中心一般有哪些测试项目以及测试流程是如何?和小编一起往下看看吧!一、软件测评中心的测试项目1、功能测试:通过模拟用户使用场景,测试软件的各项功能是否正常、稳定。2、性能测试:通......
  • 软件第三方测评机构简析:良好的测试环境对软件产品起到的作用
    近年来,软件行业发展迅速,软件产品的质量成为用户关注的焦点。而软件的质量评估往往需要依赖专业的第三方测评机构,为了更好地了解软件测试环境对产品质量的重要性,小编整理了以下简析:一、良好的测试环境对软件产品起到的作用1、为软件产品提供一个真实、稳定的运行场景,模......
  • 软件测评中心简析:办理软件测试报告的流程、周期、费用
    软件测评中心是一个专门负责软件测试和测评工作的机构,不仅承担着测试软件产品的功能和性能,还有助于评估软件在实际使用中的稳定性和可靠性。在一个良好的软件测评中心中,通常会有一支专业的测试团队,会使用各种测试技术和工具,进行测试用例设计、测试执行、缺陷管理等工作。一......
  • 谷歌广告基本的出价策略简析
    GoogleAds针对不同类型的广告系列制定了多种出价策略。您可以根据自己广告系列所定位的广告网络,以及您注意的目标(点击次数、展示次数、转化次数或观看次数)来确定最适合自己的策略。在本文中,我将介绍如何根据广告目标来选择出价策略。考虑您的目标每种出价策略分别适用于不同类型......
  • Pomelo官方demo ChatofPomelo简析之一——用户登录
    Pomelo官方demoChatofPomelo简析之一——用户登录 官方给的tutorial真是简单明了,简的刚开始学pomelo,压根就不知道代码写在哪。所以还是自己研究研究。首先看服务器端,处理逻辑的主要在game-server/app/servers下。有chat、connector和gate三种类型的服务器。connector:frontend前......
  • 01-[Linux][MFD]MFD模块介绍
    1、MFD功能介绍MFD(Multi-functionDevice)多功能设备,许多有共性的设备的集合,MFD由核心层(core)以及其下的“子设备”组成。从下文将会看到,MFD只是将设备注册到platform总线--因此,其子设备属于platform设备。它并没有对涉及到的设备或者驱动做实质性改变。但是,因为某些设备的共性,所以......
  • 【专题】2022预制菜消费市场现状和舆情简析 报告PDF合集分享(附原数据表)
    报告链接:https://tecdat.cn/?p=33388近年来,中国的预制菜行业迅速发展,已成为消费者生活中不可或缺的一部分。研究报告显示,预制菜行业在美国和日本等国家已经发展了很长时间,与中国市场相比,中国的预制菜市场仍有巨大的增长潜力。预制菜行业的蓬勃发展主要受到两个方面的推动:企业端通......
  • CAS与AQS源码简析
    什么是CAS?CAS(CompareAndSwap),顾名思义就是比较并交换。用于解决多线程使用锁带来的性能损耗的问题,是一种非阻塞算法,其交换原理如下图:   CAS用法:-数据库中的乐观锁:即表字段+version字段,然后每次更新时就比较当前version版本是否一......