linux gpio dev,Linux GPIO

本文详细介绍了Linux内核中的GPIO子系统与PinControl子系统的软件架构,包括PinController与GPIOController的功能配置,并通过Allwinner H5平台的实际代码示例展示了Pinctrl与Gpio的整合方式。
摘要由CSDN通过智能技术生成

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

前言

对于一个IO Port来讲,有两方面需要配置,一是本身的功能设定,二是如果作为GPIO的话输入输出的设定。前者由Pin Controller控制,后者由GPIO Controller控制。

Pin Controller控制包括:引脚功能配置。例如该I/O pin是一个普通的GPIO还是一些特殊功能引脚(例如memeory bank上CS信号)。

引脚特性配置。例如pull-up/down电阻的设定,drive-strength的设定等。

GPIO Controller控制包括:配置GPIO的方向

如果是输出,可以配置high level或者low level

如果是输入,可以获取GPIO引脚上的电平状态

软件架构

linux kernel中的GPIO subsystem则用两个软件模块来对应上面两类硬件功能:pin control subsystem的模块图

14e02681de0691e470cad2f2edd71068.png

底层的pin controller driver是硬件相关的模组,初始化的时候会向pin control core模块注册pin control设备(通过pinctrl_register这个bootom level interface)。pin control core模块是一个硬件无关模块,它抽象了所有pin controller的硬件特性,仅仅从用户(各个driver就是pin control subsystem的用户)角度给出了top level的接口函数,这样,各个driver不需要关注pin controller的底层硬件相关的内容。GPIO subsystem的模块图

8de6875fa883def7d884ca5b6f4a2205.png

基本上这个软件框架图和pin control subsystem是一样的,其软件抽象的思想也是一样的,当然其内部具体的实现不一样。

后对照Allwinner H5 Linux3.10的实际代码看,Pinctrl和Gpio是整合到一起的,传统gpio的调用最终还是到Pinctrl下面的API来实现。整体框架如下:

34f738e96dcc6867993cce9bb48e6710.png

1. 普通Driver如何调用pinctrl

上图从上往下看,普通Driver调用pin control subsystem的主要目标是:1.设定该设备的功能复用;2. 设定该device对应的那些pin的电气特性。以emmc模块驱动(sunxi-mmc.c)为例:

DTS中Emmc部分的配置为:1

2

3

4

5

6compatible = "allwinner,sun50i-sdmmc0";

pinctrl-names = "default","sleep";

pinctrl-0 = ;

pinctrl-1 = ;

};

Pinctrl部分的DTS配置为:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18r_pio: pinctrl@01f02c00 {

compatible = "allwinner,sun50i-r-pinctrl"

sdc0_pins_a: sdc0@0 {

allwinner,pins = "PF0", "PF1", "PF2", "PF3","PF4","PF5"

allwinner,function = "sdc0"

allwinner,muxsel = <2>

allwinner,drive = <1>

allwinner,pull = <1>

}

sdc0_pins_b: sdc0@1 {

allwinner,pins = "PF0", "PF1", "PF2", "PF3","PF4","PF5"

allwinner,function = "io_disabled"

allwinner,muxsel = <7>

allwinner,drive = <1>;

allwinner,pull = <1>;

};

其中pinctrl中有两种状态,default是默认状态,从上面dts配置可以看出配置为sdc0的Function,sleep是休眠时或是emmc关闭时调用的状态,从上可看出配置为io_disabled状态。

代码中调用的流程:1

2

3

4

5

6

7

8host->pinctrl = devm_pinctrl_get(&pdev->dev);

--- 1. 获取设备(设备模型中的struct device)的pin control state holder(struct pinctrl)

host->pins_default = pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_DEFAULT);

-- 2a. 根据state name在pin control state holder找到对应的pin control state, 这里是default

host->pins_sleep = pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_SLEEP);

-- 2b. 这里是sleep状态

ret = pinctrl_select_state(host->pinctrl , host->pins_sleep); -- 3a. 休眠时或是emmc关闭时调用

rval = pinctrl_select_state(host->pinctrl, host->pins_default); -- 3b. 打开时调用

2. 板级Pinctrl driver如何注册

pinctrl driver根据pin controller的实际情况,实现struct pinctrl_desc(包括pin/pin group的抽象,function的抽象,pinconf、pinmux的operation API实现,dt_node_to_map的实现,等等),并注册到kernel中。

代码流程–>pinctrl-sun50iw1p1.c开始:1

2

3

4

5

6

7

8--> sunxi_pinctrl_init(pdev,&sun50iw1p1_pinctrl_data); -- 其中sun50iw1p1_pinctrl_data描述了所有IO的Function及irq状况

-->

pctrl_desc->confops = &sunxi_pconf_ops; -- 操作函数是用来配置引脚的特性,如pull-up/down,driver strength

pctrl_desc->pctlops = &sunxi_pctrl_ops; -- dts 功能group的相关解析

pctrl_desc->pmxops = &sunxi_pmx_ops; -- 功能复用enable/disable,gpio方向

-->

pctl->pctl_dev = pinctrl_register(pctrl_desc,&pdev->dev, pctl); -- 注册到pin control subsystem

3. Gpio如何关联

GPIO的HW block应该和其他功能复用的block是对等关系的,它们共同输入到一个复用器block,这个block的寄存器控制哪一个功能电路目前是active的。

0812b6695678b7d10f158c8e39a5d8f5.png

代码中,sunxi_pinctrl_init(pdev,&sun50iw1p1_pinctrl_data)–>1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23pctl->chip->request = sunxi_pinctrl_gpio_request,

pctl->chip->free = sunxi_pinctrl_gpio_free,

pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input,

pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output,

pctl->chip->get = sunxi_pinctrl_gpio_get,

pctl->chip->set = sunxi_pinctrl_gpio_set,

pctl->chip->set_debounce = sunxi_pinctrl_gpio_set_debounce,

pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate,

pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq,

ret = gpiochip_add(pctl->chip);

if (ret)

goto pinctrl_error;

for (i = 0; i < pctl->desc->npins; i++) {

const struct sunxi_desc_pin *pin = pctl->desc->pins + i;

ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),

pin->pin.number - pctl->desc->pin_base,

pin->pin.number, 1);

if (ret)

goto gpiochip_error;

}

通过gpiochip_add(gpiolib.c)将 pctl->chip中指定的api与gpio子系统关联起来,以gpiod_direction_output为例:1

2

3

4

5

6

7

8

9gpiod_direction_output ---->

chip->direction_output(chip, offset, value) ---->

pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output ---->

pinctrl_gpio_direction_output(chip->base + offset) ---->

pinctrl_gpio_direction(gpio, false) ---->

pinmux_gpio_direction(pctldev, range, pin, input) ---->

ops->gpio_set_direction(pctldev, range, pin, input) ---->

sunxi_pmx_gpio_set_direction ----> pinmux_ops里面的callback,所以最终回到pinctrl driver

sunxi_pmx_set(pctldev, offset, desc->muxval, true) -- 最终控制 寄存器的地方

以上只是根据allwinner H5实际代码大略分析,具体可以参考以下。

refs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值