coding无法使用浏览器打开,必须用git工具下载:
git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
参考资料:
记住pinctrl的三大作用,有助于理解所涉及的数据结构:
pincontroller虽然是一个软件的概念,但是它背后是有硬件支持的,所以可以使用一个结构体来表示它:pinctrl_dev。
怎么构造出pinctrl_dev?我们只需要描述它:提供一个pinctrl_desc,然后调用pinctrl_register就可以:
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data);
怎么使用pinctrl_desc、pinctrl_dev来描述一个pin controller?这两个结构体定义如下:
pinctrl_desc示例如下:
使用结构体pinctrl_pin_desc来描述一个引脚,一个pin controller有多个引脚:
使用pinctrl_ops来操作引脚,主要功能有二:
调用devm_pinctrl_register或pinctrl_register,就可以根据pinctrl_desc构造出pinctrl_dev,并且把pinctrl_dev放入链表:
devm_pinctrl_register
pinctrl_register
struct pinctrl_dev *pctldev;
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
/* check core ops for sanity */
ret = pinctrl_check_ops(pctldev);
/* If we're implementing pinmuxing, check the ops for sanity */
ret = pinmux_check_ops(pctldev);
/* If we're implementing pinconfig, check the ops for sanity */
ret = pinconf_check_ops(pctldev);
/* Register all the pins */
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
list_add_tail(&pctldev->node, &pinctrldev_list);
在设备树中,使用pinctrl时格式如下:
/* For a client device requiring named states */
device {
pinctrl-names = "active", "idle";
pinctrl-0 = <&state_0_node_a>;
pinctrl-1 = <&state_1_node_a &state_1_node_b>;
};
设备节点要么被转换为platform_device,或者其他结构体(比如i2c_client),但是里面都会有一个device结构体,比如:
每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息:
假设芯片上有多个pin controller,那么这个设备使用哪个pin controller?
这需要通过设备树来确定:
设备引用pin controller中的某个节点时,这个节点会被转换为一些列的pinctrl_map:
pinctrl-0 = <&state_0_node_a>
调用过程:
really_probe
pinctrl_bind_pins
pinctrl_select_state
/* Apply all the settings for the new state */
list_for_each_entry(setting, &state->settings, node) {
switch (setting->type) {
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_enable_setting(setting);
ret = ops->set_mux(...);
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_apply_setting(setting);
ret = ops->pin_config_group_set(...);
break;
default:
ret = -EINVAL;
break;
}
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_apply_setting(setting);
ret = ops->pin_config_group_set(...);
break;
default:
ret = -EINVAL;
break;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/94254633e52d4b7e8e664ca77a4e158d.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3RoaXN3YXlfZGl5,size_16,color_FFFFFF,t_70)