1. 程式人生 > >linux裝置驅動模型 - regmap

linux裝置驅動模型 - regmap

1. regmap介紹

regmap主要是為了方便操作暫存器而設計的,它將所有模組的暫存器(包括soc上模組的暫存器和外圍裝置的暫存器等)
抽象出來,用一套統一介面來操作暫存器

比如,如果要操作i2c裝置的暫存器,那麼就要呼叫i2c_transfer介面,要操作spi裝置的暫存器,就要呼叫spi_write/spi_read等介面,
如果把它們都抽象為regmap結構,那麼只要呼叫regmap_read/regmap_write就可以了

regmap的程式碼在目錄:drivers/base/regmap

目前regmap抽象的裝置主要分兩種型別,一種是cache型別的,這種裝置就是把暫存器值寫入到記憶體中,
另一種是實際的硬體裝置,暫存器的值要寫入實際的模組中

在核心版本4.14上,cache的型別有3中:
- flat:普通陣列型別
- rb-tree:紅黑樹型別
- lzo:壓縮型別

 enum regcache_type {
    REGCACHE_NONE,
    REGCACHE_RBTREE,
    REGCACHE_COMPRESSED,
    REGCACHE_FLAT,
 };

實際的硬體裝置實現regmap的有:I2C/SPI/spmi/mmio等,後面會舉例介紹一下mmio

2. regmap設計框架

regmap的整個框架如下:

這裡寫圖片描述

2.1 regmap結構體

簡單介紹下regmap結構體

struct regmap {
    。。。。。。
    struct device *dev; /* Device we do I/O on */
    void *work_buf;     /* Scratch buffer used to format I/O */
    struct regmap_format format;  /* Buffer format */
    const struct regmap_bus *bus;-------------regmap裝置匯流排
    void *bus_context;------------------------匯流排私有資料
    const char *name;

    unsigned int max_register;
    /×判斷是否可讀寫的函式×/
    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);
    /×讀寫暫存器函式×/
    int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
    int (*reg_write)(void *context, unsigned int reg, unsigned int val);
    int (*reg_update_bits)(void *context, unsigned int reg,
                   unsigned int mask, unsigned int val);
    /×讀寫掩碼×/
    unsigned long read_flag_mask;
    unsigned long write_flag_mask;

    /* number of bits to (left) shift the reg value when formatting*/
    int reg_shift;------------暫存器偏移
    int reg_stride;-----------暫存器對齊位
    int reg_stride_order;

    /×regcache相關的函式×/
    /* regcache specific members */
    const struct regcache_ops *cache_ops;
    enum regcache_type cache_type;

    /* number of bytes in reg_defaults_raw */
    unsigned int cache_size_raw;
    /* number of bytes per word in reg_defaults_raw */
    unsigned int cache_word_size;
    /* number of entries in reg_defaults */
    unsigned int num_reg_defaults;
    /* number of entries in reg_defaults_raw */
    unsigned int num_reg_defaults_raw;

    /* if set, only the cache is modified not the HW */
    bool cache_only;
    /* if set, only the HW is modified not the cache */
    bool cache_bypass;
    /* if set, remember to free reg_defaults_raw */
    bool cache_free;

    /×多暫存器讀寫相關欄位×/
    /* if set, converts bulk read to single read */
    bool use_single_read;
    /* if set, converts bulk read to single read */
    bool use_single_write;
    /* if set, the device supports multi write mode */
    bool can_multi_write;

    /* if set, raw reads/writes are limited to this size */
    size_t max_raw_read;---------能讀的暫存器範圍
    size_t max_raw_write;--------能寫的暫存器範圍
。。。。。。
};

2.2 regmap_config結構體

我們要建立自己的regmap的時候,一般會先初始化regmap_config結構體,然後進行regmap的建立

struct regmap_config {
    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);

    int (*reg_read)(void *context, unsigned int reg, unsigned int *val);---暫存器讀函式
    int (*reg_write)(void *context, unsigned int reg, unsigned int val);---暫存器寫函式

    unsigned int max_register;------------最大暫存器地址

    enum regcache_type cache_type;--------regmap型別

    unsigned long read_flag_mask;---------讀掩碼
    unsigned long write_flag_mask;--------寫掩碼

    enum regmap_endian reg_format_endian;-----暫存器地址大小端
    enum regmap_endian val_format_endian;-----暫存器值大小端
};

2.3 regmap建立

2.3.1 __devm_regmap_init

呼叫devm介面方便驅動解除安裝的時候釋放資源

2.3.2 __regmap_init

init的過程如下:

  1. config的lock配置給regmap
  2. config的reg-bit/val-bit等配置給regmap
  3. 把regmap_bus給regmap
  4. 把config的讀寫判斷函式(writeable_reg/readable_reg)等相關配置給regmap
  5. 如果regmap_bus不為空,那麼把regmap_bus的讀寫函式給regmap,否則把config的配置給regmap
  6. 給regmap提供資料格式化format的相關函式

2.4 常用暫存器操作介面

使用regmap讀寫暫存器的介面有:

static inline int regmap_write(struct regmap *map, unsigned int reg,
               unsigned int val)
static inline int regmap_read(struct regmap *map, unsigned int reg,
              unsigned int *val)
static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
               void *val, size_t val_count)
static inline int regmap_update_bits_base(struct regmap *map, unsigned int reg,
                  unsigned int mask, unsigned int val,
                  bool *change, bool async, bool force)

3. regmap用例(regmap-mmio)

regmap-mmio是用來對映soc上的模組暫存器,方便驅動操作模組而設計的

3.1 regmap-mmio的建立

可以呼叫函式:

struct regmap *__regmap_init_mmio_clk(...)

struct regmap *__devm_regmap_init_mmio_clk(...)

建立過程:
1. 先初始化regmap-mmio的私有結構體:regmap_mmio_context
主要是分配讀寫函式和clock
2. 然後進行regmap的初始化,使用regmap_bus匯流排為regmap_mmio