Linux内核中提供了pinctrl子系统,目的是为了统一各SoC厂商的pin脚管理,避免各SoC厂商各自实现相同的pin脚管理子系统,减少SoC厂商系统移植工作量。
1. 管理系统中所有可以控制的pin。在系统初始化的时候,枚举所有可以控制的pin,并标识这些pin。
2. 管理这些pin的复用(Multiplexing)。对于SOC而言,其引脚除了配置成普通GPIO之外,若干个引脚还可以组成一个pin group,形成特定的功能。例如pin number是{ 0, 8, 16, 24 }这四个引脚组合形成一个pin group,提供SPI的功能。pin control subsystem要管理所有的pin group。
3. 配置这些pin的特性。例如配置该引脚上的pull-up/down电阻,配置drive strength等。
4. 与GPIO子系统的交互
5. 实现pin中断
kernel配置文件: lichee/linux-3.4/arch/arm/configs/sun8iw7p1smp_android_defconfig
系统配置文件:lichee\tools\pack\chips\sun8iw7p1\configs\dolphin-p1\sys_config.fex
arch/arm/mach-sunxi/ sys_config.c //分析、处理sys_config.fex文件。
drivers/pinctrl/ core.c //创建debug fs,提供pinctrl_register等函数接口。
drivers/pinctrl/ pinctrl-sun8iw7.c //该平台下的pin脚数据
(1) drivers/pinctrl/ pinctrl-sunxi.c
1 sunxi_pinctrl_probe函数:
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); // devm_kzalloc基于slab分配在物理上连续的实际的内存, 并且带有释放内存的回调函数,当该设备与驱动分开时,自动释放内存。
pctl->desc = (struct sunxi_pinctrl_desc *)(&sunxi_pinctrl_data);
1.1 sunxi_pinctrl_build_state(pdev);//将pctl->desc的子项数据复制到pctl相应子项。
1.2 pctl->pctl_dev = pinctrl_register(&sunxi_pctrl_desc, &pdev->dev, pctl); //创建pinctrl_dev设备,调用pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);注册所有的pin。
1.2.1 pinctrl_register_pins对每一个pin脚调用 ret=pinctrl_register_one_pin(pctldev, pins[i].number, pins[i].name); //将pin 的物理地址,名字存入pin_desc结构体,将该结构体加入pin_desc_tree链表。
1.2.2 pctldev->p = pinctrl_get_locked(pctldev->dev); //先调用find_pinctrl从pinctrl_list链表中查找看pin control state holder是否存在;存在,即表明其正在使用中;不存在时,调用create_pinctrl创建pinctrl,从pinctrl_maps链表查找对应dev的maps_node,而maps里面的数据是从sys_config.fex文件分析获取,详见1.5。如找到对应的maps_node,则调用add_setting(p, map);该函数针对map->type填充pinctrl_setting相应成员变量,如果是PIN_MAP_TYPE_MUX_GROUP类型,填充之后,还会调用pin_request注册同组中所有的pin。
最后将pinctrl加入pinctrl_list链表。
1.2.3 pinctrl_init_device_debugfs(pctldev); //注册debugfs
1.3 gpiochip_add //GPIO驱动将通过chip来与pinctrl联系,相应的操作将通过sunxi_pinctrl_gpio_chip结构的方法成员实现相应的操作。
将全局变量gpio_desc的成员变量chip、flags赋初值。后续GPIO相应操作将通过gpio_desc进行。
1.3.1 of_gpiochip_add(chip);
初始化chip的相应变量,并增加chip->of_node的引用计数
1.3.2 gpiochip_export(chip)
创建gpiochip0设备,其属性文件用来show chip->ngpio, chip->label, chip->base
1.4 gpiochip_add_pin_range 建立动态链表chip->pin_ranges,node为gpio_pin_range,其成员range包含pin脚基地址。
1.5 sunxi_pinctrl_parse_pin_cfg (pdev); //分析获取sys_config.fex文件中的配置,
1.5.1 sunxi_pinctrl_creat_mappings(pdev, pin_count, pin_list, device_name, state_name); //用配置数据填充pinctrl_map
1.5.2 pinctrl_register_mappings //创建pinctrl_maps,将pinctrl_map赋值给其maps成员变量,并加入pinctrl_maps链表。
1.6 sunxi_eint_gpio_init //注册中断
(2) drivers/gpio/ gpio-sunxi.c
1. gpio_sw_init // 读取sys_config.fex文件中gpio_para参数对应的配置数据组,有单独led_assign进行处理
1.1 gpio_request //向pinctrl请求pin用作GPIO,成功后,该Pin仅能被GPIO驱动所使用,不能被其他驱动所混用
通过本文件的静态结构数组gpio_desc找到对应的pin脚的设置,具体数据见Pinctrl-sun8iw7.c (drivers\pinctrl)
chip->request 等价于执行 sunxi_pinctrl_gpio_chip. Request = sunxi_pinctrl_gpio_request
-> pinctrl_request_gpio -> pinmux_request_gpio -> pin_request -> pctldev->desc->pmxops->
(1. gpio_request_enable 2. request)
1.2 platform_device_register(gpio_sw_dev[i]) //注册平台设备
gpio_sw_dev[i]->name = "gpio_sw";
gpio_sw_dev[i]->id = i;
gpio_sw_dev[i]->dev.platform_data = sw_pdata[i];
gpio_sw_dev[i]->dev.release = gpio_sw_release;
1.3 platform_driver_register(&gpio_sw_driver)
注册gpio_sw驱动,
gpio_sw_probe: 调用gpio_sw_cfg_set及gpio_sw_data_set函数根据参数配置设置,调用gpio_sw_classdev_register创建相应的设备属性文件,即提供接口给上层,如上接,写1/0等操作。根据sw_pdata->link创建超链接
/sys/class/gpio_sw /normal_led -> PA15
/sys/class/gpio_sw /standby_led -> PL10
/sys/devices/platform/gpio_sw.0/gpio_sw/PL10/cfg
/sys/devices/platform/gpio_sw.1/gpio_sw/PA15/cfg
1. 非GPIO驱动模块使用的接口:
pinctrl_get //获取设备的pin操作句柄
struct pinctrl *pinctrl_get(struct device *dev) à p = pinctrl_get_locked(dev);
第641行调用find_pinctrl函数
第645行调用create_pinctrl,获取pinctrl结构体
pinctrl_put
devm_pinctrl_get
devm_pinctrl_put
pinctrl_lookup_state //查找pinctrl_state
pinctrl_select_state //将pin句柄对应的pinctrl设置为state句柄对应的状态,其核心为通过pinmux_enable_setting或pinconf_apply_setting来调用pinctrl_desc的ops来设置pin状态。
devm_pinctrl_get_select
devm_pinctrl_get_select_default
pin_config_get //获取指定pin的属性,最终是通过confops->pin_config_get获取
pin_config_set //设置指定pin的属性,最终是通过confops->pin_config_set设置
pin_config_group_get //与上类似,pin_config_group_get
pin_config_group_set //与上类似,pin_config_group_set
drivers/gpio/ gpiolib.c
gpio_request
gpio_free
gpio_direction_input
gpio_direction_output
__gpio_get_value
__gpio_set_value
1. GPIO口配置:
lichee/tools/pack/chips/sun8iw7p1/configs/dolphin-p1/sys_config.fex 参照如下配置即可:
;----------------------------------------------------------------------------------
;userspace gpio interface for android
;----------------------------------------------------------------------------------
[gpio_para]
gpio_used = 1
gpio_num = 2
gpio_pin_1 = port:PL10<1>
gpio_pin_2 = port:PA15<1>
a. 向应用层提供的接口文件如下:
/sys/devices/platform/gpio_sw.0/gpio_sw/PL10/
/sys/devices/platform/gpio_sw.1/gpio_sw/PA15/
b. 内核其他模块使用:
#include
__gpio_get_value
__gpio_set_value
2. 非GPIO驱动模块的使用
#include
devm_pinctrl_get
pinctrl_lookup_state
pinctrl_select_state
1.《H3 Pinctrl(GPIO)接口使用说明V1.0.pdf》
2. http://www.wowotech.net/gpio_subsystem/pin-control-subsystem.html/ comment-page-2#comments