全志H3平台pinctrl模块分析

概要

Linux内核中提供了pinctrl子系统,目的是为了统一各SoC厂商的pin脚管理,避免各SoC厂商各自实现相同的pin脚管理子系统,减少SoC厂商系统移植工作量。

1.1 主要功能

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中断

1.2 核心驱动源码文件

全志H3平台pinctrl模块分析_第1张图片

1.3 总体框架

全志H3平台pinctrl模块分析_第2张图片

2源码分析

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脚数据

2.1 驱动加载时主流程代码

(1) drivers/pinctrl/ pinctrl-sunxi.c

全志H3平台pinctrl模块分析_第3张图片

全志H3平台pinctrl模块分析_第4张图片

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链表查找对应devmaps_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的成员变量chipflags赋初值。后续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_rangesnodegpio_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

2.2 向其他驱动模块提供的接口函数

1. GPIO驱动模块使用的接口:

pinctrl_get //获取设备的pin操作句柄

struct pinctrl *pinctrl_get(struct device *dev) à p = pinctrl_get_locked(dev); 

全志H3平台pinctrl模块分析_第5张图片

第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_descops来设置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

2.3 GPIO驱动使用的接口

drivers/gpio/ gpiolib.c

gpio_request

gpio_free

gpio_direction_input

gpio_direction_output

__gpio_get_value

__gpio_set_value

2.4 各数据之间的联系图

全志H3平台pinctrl模块分析_第6张图片

3 使用方法及实例

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><1>

gpio_pin_2      = port:PA15<1><0>

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

4 参考文献

1.H3 Pinctrl(GPIO)接口使用说明V1.0.pdf

2. http://www.wowotech.net/gpio_subsystem/pin-control-subsystem.html/ comment-page-2#comments


你可能感兴趣的:(work)