一、pinctrl注册函数
int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
| struct device *dev,
| void *driver_data,
| struct pinctrl_dev **pctldev)
|-->static struct pinctrl_dev * pinctrl_init_controller(
| struct pinctrl_desc *pctldesc,
| struct device *dev,
| void *driver_data)
|-->static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pins, //pin描述符数组
unsigned int num_descs) //pin描述符数组长度,即pin数量
二、pinctrl使能函数
在驱动初始化探测过程调用注册函数pinctrl_register_and_init之后,还需要直接调用使能函数pinctrl_enable。
static LIST_HEAD(pinctrldev_list); //pin控制器设备全局链表
int pinctrl_enable(struct pinctrl_dev *pctldev)
|
|--> static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
|
|-->static struct pinctrl *create_pinctrl(struct device *dev,
struct pinctrl_dev *pctldev)
|
|-->struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
const char *name)
|
|-->int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
| |->pinctrl_commit_state
|-->pinctrl_lookup_state()
|
|--> list_add_tail(&pctldev->node, &pinctrldev_list); //将本设备插入全局链表
- pinctrl_lookup_state根据名称查询pinctrl结构是否存在要查找的状态,状态有“default”、“init”、“idle”、“sleep”四种,这四种描述了控制器的硬件状态。
- pinctrl_select_state将硬件设置到一种新的pinctrl状态,硬件状态由pinctrl结构保存。从老状态退出需要调用pinmux_disable_setting,新状态才能使能生效通过调用pinmux_enable_setting和pinconf_apply_setting,最后再修改pinctrl结构的状态信息。
三、核心数据结构
2.1 pinctrl_desc描述符
struct pinctrl_desc { const char *name; //pinctrl驱动名称 const struct pinctrl_pin_desc *pins;//pin描述符数组 unsigned int npins; //pin描述符数组长度,即pin数量 const struct pinctrl_ops *pctlops; //pinctrl操作向量表,用于支持pin分组等全局操作 const struct pinmux_ops *pmxops; //pinmux操作向量表,如果本驱动支持pin复用操作 const struct pinconf_ops *confops; //pinconf操作向量表,如果本驱动支持pin配置操作 struct module *owner; //指向pinctrl驱动所属的内核模块 bool link_consumers; //所有请求pinctrl驱动服务的消费者链表 };
2.2 pinctrl_pin_desc描述符
struct pinctrl_pin_desc { unsigned int number; //pin编号,即pinctrl驱动范围内的唯一编号 const char *name; //pin名称 void *drv_data; //pinctrl驱动指针 }; #define PINCTRL_PIN(a, b) { .number = a, .name = b }
pinctrl的设备驱动程序一般用PINCTRL_PIN宏来静态定义所有pin描述符数组:
static const struct pinctrl_pin_desc tegra_dpaux_pins[] =
{
PINCTRL_PIN(0, "DP_AUX_CHx_P"),
PINCTRL_PIN(1, "DP_AUX_CHx_N"),
};
2.3 pingroup描述符
struct pingroup { const char *name; //pingroup名称 const unsigned int *pins; //分组内的pin编号数组 size_t npins; //数组长度 };
#define PINCTRL_PINGROUP(_name, _pins, _npins) \ (struct pingroup) { \ .name = _name, \ .pins = _pins, \ .npins = _npins, \ }
pinctrl的设备驱动程序一般用PINCTRL_PINGROUP宏来静态定义所有pin分组:
static const unsigned int cs42l43_pin_gpio1_pins[] = { 0 };
static const unsigned int cs42l43_pin_gpio2_pins[] = { 1 };
static const unsigned int cs42l43_pin_gpio3_pins[] = { 2 };
static const unsigned int cs42l43_pin_asp_pins[] = { 3, 4, 5 };
static const unsigned int cs42l43_pin_pdmout2_pins[] = { 6, 7 };
static const unsigned int cs42l43_pin_pdmout1_pins[] = { 8, 9 };
static const unsigned int cs42l43_pin_i2c_pins[] = { 10, 11 };
static const unsigned int cs42l43_pin_spi_pins[] = { 12, 13, 14 };
#define CS42L43_PINGROUP(_name) \
PINCTRL_PINGROUP(#_name, cs42l43_pin_##_name##_pins, \
ARRAY_SIZE(cs42l43_pin_##_name##_pins))
static const struct pingroup cs42l43_pin_groups[] = {
CS42L43_PINGROUP(gpio1),
CS42L43_PINGROUP(gpio2),
CS42L43_PINGROUP(gpio3),
CS42L43_PINGROUP(asp),
CS42L43_PINGROUP(pdmout2),
CS42L43_PINGROUP(pdmout1),
CS42L43_PINGROUP(i2c),
CS42L43_PINGROUP(spi),
};
四、操作
3.1 分组操作
- get_groups_count:获取全局的分组数量;
- get_group_name: 获取指定分组的组名称;
- get_group_pins: 获取指定分组的pin编码数组和数组长度;
- dt_node_to_map: 分配设备树“pin configuration node”,并创建相应的映射表,返回pinctrl_map表项数组和数组长度,如果pinctrl设备驱动不支持设备树,该操作为NULL;
- dt_free_map: 释放映射表;也就是说允许pinctrl驱动根据设备树动态映射和释放映射表。
注意:Linux内核称分组操作为全局性操作,主要原因是:pinctrl有两个基本功能,复用和配置。
3.2 复用操作
复用是指,芯片pin信号可以连接内部多个功能部件,在一个时刻,pin只能由其中的一个功能部件使用。
- request:pinctrl框架层调用该方式判断给定的pin是否可以复用;如果不满足复用条件,返回一个负的错误码。对于一个指定pin,request操作一旦成功相当于申请到该pin的复用权限;
- free:在pinctrl框架层调用request操作成功之后,pinctrl框架层才能调用free操作释放指定的pin;
- get_function_count:返回pinctrl驱动管理的复用功能的数量;
- get_function_name:返回指定编号的复用功能名称;
- get_function_group:返回指定编号的复用功能对应的分组名称,这样再通过全局/分组操作来获取相应的pin。注意,该操作可能返回多个分组名称。
- set_mux:在指定pin分组上将指定的复用功能使能。该函数不需要考虑指定pin分组其他复用功能的冲突问题;因为冲突有pinctrl/pinmux框架处理。
- gpio_request_enable:在指令pin上请求和使能GPIO功能。当pinctrl所管理的每一个pin都可以独立成为GPIO时,可以实现该函数。gpio相关的操作的pin集合,是以pinctrl_gpio_range描述符来定义的,这个概念与前面介绍的复用功能和pin分组是两个维度。pinctrl框架层来处理以保证不发生冲突。
- gpio_disable_free: gpio_request_enable的反向操作。
- gpio_set_direction: 设置方向。
3.3 配置操作
该配置操作是设置和查询pin或pin分组的方向特性、开/漏等电气特性。
- pin_config_get/set
- pin_config_group_get/sisi