zoukankan      html  css  js  c++  java
  • 内核regmap机制【转】

    转自:https://blog.csdn.net/heabby2010/article/details/79063949?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

    内核版本:3.10.92

    内核3.1引入了一套新的API机制:regmap,主要为I2C,SPI,IRQ等操作提供统一接口,提高代码可重用性,减少重复逻辑。

    以I2C为例:

    要让设备跟I2C通信,以前的办法是调用i2c_transfer接口,其实regmap最终还是调用到i2c_transfer,只不过中间加了一层缓冲,这样统一了接口,减少了底层I/O的操作次数。

    在初始化之前,要先填充regmap_config结构体。

    先看看定义:


    struct regmap_config {
    const char *name;

    int reg_bits;//寄存器地址位数,必须配置
    int reg_stride;
    int pad_bits;//寄存器和值之间的填充位数
    int val_bits;//寄存器值的位数,必须配置

    bool (*writeable_reg)(struct device *dev, unsigned int reg);
    bool (*readable_reg)(struct device *dev, unsigned int reg);
    bool (*volatile_reg)(struct device *dev, unsigned int reg);
    bool (*precious_reg)(struct device *dev, unsigned int reg);
    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;
    const struct regmap_access_table *wr_table;
    const struct regmap_access_table *rd_table;
    const struct regmap_access_table *volatile_table;
    const struct regmap_access_table *precious_table;
    const struct reg_default *reg_defaults;
    unsigned int num_reg_defaults;
    enum regcache_type cache_type;
    const void *reg_defaults_raw;
    unsigned int num_reg_defaults_raw;

    u8 read_flag_mask;
    u8 write_flag_mask;

    bool use_single_rw;

    enum regmap_endian reg_format_endian;
    enum regmap_endian val_format_endian;

    const struct regmap_range_cfg *ranges;
    unsigned int num_ranges;
    };
    注册:

    struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
    const struct regmap_config *config)
    读写I2C:

    int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);//读取reg中的值,保存在val中
    int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
    size_t val_len); //从reg中读取val_len长度的数据,保存在val中
    int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);//将val写入到reg中
    int regmap_raw_write(struct regmap *map, unsigned int reg,
    const void *val, size_t val_len);//将val写入到reg中,val长度为val_len
    int regmap_update_bits(struct regmap *map, unsigned int reg,
    unsigned int mask, unsigned int val)//更新reg中指定的位


    看下注册过程:

    regmap_init_i2c -> //regmap-i2c.c

    regmap_init-> //多了两个参数,最重要是第二个regmap_bus regmap_i2c,实现了I2C的读写,SPI同理

    map->reg_read  = _regmap_bus_read; //绑定读函数

    map->reg_write = _regmap_bus_raw_write; //绑定写函数

    看下读写过程:
    读:

    regmap_read ->

    _regmap_read ->

    map->reg_read -> //初始化时已经绑定_regmap_bus_read

    _regmap_bus_read->

    _regmap_raw_read ->

    map->bus->read    //调用regmap-i2c.c中实现的regmap_i2c.read

    写:

    regmap_write->
    _regmap_write ->

    map->reg_write  -> //初始化时已经绑定_regmap_bus_raw_write

    _regmap_bus_raw_write->

    _regmap_raw_write->

    map->bus->write //调用regmap-i2c.c中实现的regmap_i2c.write


    最后看看regmap-i2c.c吧


    static int regmap_i2c_write(void *context, const void *data, size_t count)
    {
    struct device *dev = context;
    struct i2c_client *i2c = to_i2c_client(dev);
    int ret;

    ret = i2c_master_send(i2c, data, count);
    if (ret == count)
    return 0;
    else if (ret < 0)
    return ret;
    else
    return -EIO;
    }
    static int regmap_i2c_read(void *context,
    const void *reg, size_t reg_size,
    void *val, size_t val_size)
    {
    struct device *dev = context;
    struct i2c_client *i2c = to_i2c_client(dev);
    struct i2c_msg xfer[2];
    int ret;

    xfer[0].addr = i2c->addr;
    xfer[0].flags = 0;
    xfer[0].len = reg_size;
    xfer[0].buf = (void *)reg;
    #ifdef CONFIG_I2C_ROCKCHIP_COMPAT
    xfer[0].scl_rate = 100*1000;
    #endif

    xfer[1].addr = i2c->addr;
    xfer[1].flags = I2C_M_RD;
    xfer[1].len = val_size;
    xfer[1].buf = val;
    #ifdef CONFIG_I2C_ROCKCHIP_COMPAT
    xfer[1].scl_rate = 100*1000;
    #endif

    ret = i2c_transfer(i2c->adapter, xfer, 2);
    if (ret == 2)
    return 0;
    else if (ret < 0)
    return ret;
    else
    return -EIO;
    }
    熟悉吧,跟我们之前调用I2C的方法是一样的。
    ————————————————
    版权声明:本文为CSDN博主「板砖先生」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/heabby2010/article/details/79063949

  • 相关阅读:
    【重温设计模式】之005单例模式
    【重温设计模式】之004抽象工厂模式
    【重温设计模式】之003工厂方法模式
    【重温设计模式】之002简单工厂模式
    【重温设计模式】之001概述
    【工具】之003-Windows下常用工具
    【工具】之002-Mac下常用工具
    【工具】之001-CentOS7 最小化安装配置
    做人要精致,做事要靠谱
    Vue+Vue-router微信分享功能
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/12458857.html
Copyright © 2011-2022 走看看