一、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