一、Pinctrl子系统介绍
- 描述引脚
- 复用引脚
- 配置引脚
二、Pinctrl子系统的三层
- 用户层,作为使用pinctrl子系统的消费者,在设备树中定义pinctrl的状态,并对某种状态引用pinctrl-controller的某个节点
- 核心层,core.c,提供了pinctrl-device相关的结构体、pinctrl-desc相关的结构体、还有一些generic的ops函数
- 控制器层,作为使用pinctrl子系统的生产者,提供了不同pinctrl配置的节点定义
三、典型的设备树文件
/{
pinctrl_virt: virtual_pincontroller {
compatible = "user,virtual_pinctrl";
xx_func: xx_func {
functions = "i2c", "i2c";
groups = "pin0", "pin1";
configs = <0x11223344 0x55667788>;
};
};
my_i2c {
compatible = "user,i2c";
pinctrl-names = "default";
pinctrl-0 = <&xx_func>;
};
};
四、重要结构体
struct pinctrl_dev{ // 描述pinctrl控制器
struct list_head node; // 管理device的链表
struct pinctrl_desc *desc; // 主体,操作函数,类似gpiochip
...
};
struct pinctrl_desc{
const struct pinctrl_pin_desc *pins; // 每项表示一个引脚
unsigned int npins; // 引脚数
const struct pinctrl_ops *pctlops; // 描述引脚ops
const struct pinmux_ops *pmxops; // 复用引脚ops
const struct pinconf_ops *confops; // 配置引脚ops
...
};
struct pinctrl_pin_desc{ // 描述一个引脚
unsigned number; // 引脚编号,应独一无二
const char *name; // 引脚名称
void *drv_data; // 驱动数据
};
struct pinctrl // 对于每个device都会抽象出一个pinctrl结构体
{
...
struct pinctrl_state *state; // 存储有settings链表
struct list_head dt_maps; // maps链表
...
};
五、驱动程序流程
// 控制器驱动
1. 分配pinctrl_desc结构体
2. 设置pinctrl_desc结构体,pins、npins、pctlops、pmxops、confops
pins指向存储有所有pin信息的pinctrl_pin_desc结构体数组
npins表示引脚数目
pctlops描述引脚用操作函数get_group_count/name/pins,dt_node_to_map,dt_free_map,前三个是获得引脚的一些信息,第四个函数是解析设备树将一个设备树节点解析成一个pinctrl_map成员(一个引脚解析一个muxmap和一个confmap),第五个函数是释放pinctrl_map成员
pmxops描述引脚复用函数pmx_get_function_count/name/groups,pmx_set,前三个是获得引脚组的一些信息,第四个是设置复用函数
confops描述引脚配置函数,由pinconf_set和pinconf_get函数
3. 使用pinctrl_register注册pinctrl_desc结构体,构造pinctrl_dev结构体
// 设备驱动
1. 只需要在设备树中指定pinctrl信息
2. 当设备切换状态时,pinctrl会自动调用
六、sysfs接口
ls /sys/kernel/debug/pinctrl
// 会显示pinctrl控制器的信息
// 进入对应目录可以查看对应控制器的信息pins、pinmux、pinconf以及gpio-ranges
七、一些概念
- 引脚组,groups,一组具有相似功能的引脚的集合
- 功能,function,定义了芯片上具有外设功能的功能,一个功能对应多个引脚组
八、一些关键函数
// 注册一个pinctrl设备,根据pinctrl_desc得到pinctrl_dev
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data);
// 其中实现一,初始化pinctrl_dev结构体并pinctrl_register_pins注册所有引脚
pinctrl_init_controller
// 其中实现二,挂载到pinctrldev_list链表中
pinctrl_enable
// pinctrl绑定引脚
int pinctrl_bind_pins(struct device *dev);
九、pinctrl如何自动被调用
- 平台驱动和平台设备匹配后,平台驱动的probe函数被调用
- 具体会调用到
int really_probe(struct device *dev, struct device_driver *drv)
- 在probe之前会执行
pinctrl_bind_pins完成pinctrl的设置,通过pinctrl_lookup_state获得default的状态,通过pinctrl_select_state设置属性
- 引脚如何自动设置复用,为何是默认的default,在
pinctrl_bind_pins下的pinctrl_select_state的pinctrl_commit_state的pinmux_enable_setting的ops->set_mux
- 引脚的电气属性在哪里被配置,在
pinctrl_bind_pins下的pinctrl_select_state的pinctrl_commit_state的pinconf_apply_setting的ops->pin_config_set