X-026-KERNEL-Linux gpio driver的移植之gpio range

作者:wowo 发布于:2017-9-27 22:27 分类:X Project

1. 前言

我们在[1][2]中提到过,鉴于gpio的特殊性,pinctrl subsystem特意留了一个后门(gpio range),gpio driver可以通过这个后门直接向pinctrl subsystem申请将某个pin用作gpio功能。本文将根据一个简单的示例,介绍这个后门的使用方法,以加深对相关机制的理解。

注1:本文的测试方法和[3]中的一致,即:通过gpiolib sysfs api控制LED0(GPIOA19)的亮灭,因而不再罗列详细步骤。

2. 移植步骤

由[2]可知,gpio range的主要目的就是将gpio命名空间(gpio)转换为pinctrl命名空间(pin),并由pinctrl subsystem访问硬件实现gpio有关的功能控制。因此gpio range的移植步骤注要包括:

2.1 pinctrl命名空间和gpio命名空间的定义

参考”X-025-KERNEL-Linux gpio driver的移植之基本功能[3]”中有关gpiochip的实现,本例中的GPIOA19的gpio命名空间为:

gpiochip:gpioa
编号:19

同理,按照“X-023-KERNEL-Linux pinctrl driver的移植[4]”中的方法,结合bubblegum-96的原理图,我们可以把GPIOA19所在的管脚编号为"F3",它对应的pinctrl命名空间为:

pin controller:pinctrl@0xe01b0000
编号:52

@@ -68,6 +68,7 @@ static const struct pinctrl_pin_desc s900_pins[] = {
        PINCTRL_PIN(15, "B6"),
        PINCTRL_PIN(24, "C5"),
        PINCTRL_PIN(37, "D8"),
+       PINCTRL_PIN(52, "F3"),
        PINCTRL_PIN(60, "G1"),
         PINCTRL_PIN(61, "G2"),
  };

2.2 将gpio number转换为pin number

命名空间定义完成后,可以按照[2]中的步骤,在dts中定义一个gpio range,将gpio number转换为pin number,如下:

@@ -39,7 +39,7 @@
                clock-frequency = <24000000>;
        };

-       pinctrl@0xe01b0000 {
+       pinctrl1: pinctrl@0xe01b0000 {
                 compatible = "actions,s900-pinctrl";
                 reg = <0 0="" 0xe01b0000="" 0x550="">;

@@ -56,6 +56,7 @@
        gpioa: gpio@0xe01b0000 {
                 compatible = "actions,s900-gpio";
                reg = <0 0="" 12="" 0xe01b0000="">;
                base = <0>;
+               gpio-ranges = <&pinctrl1 19 52 1>;
        };

其中黄色背景那一行的含义是:将gpioa中的19号gpio,和pinctrl1中的52号pin,对应。

2.3 修改gpio driver和pinctrl driver,二者配合,完成gpio的request、free、direction_input以及direction_output等操作

1)修改pinctrl driver,实现pinmux_ops中gpio_request_enable、gpio_disable_free、gpio_set_direction等回调函数

这三个API的输入参数都是range指针和offset(如下所示),通过它们可以找到这个GPIO所在的gpiochip、GPIO bank、GPIO number、对应pin所在的pin controller、pin number等信息。基于这些信息,可以获得相应的硬件信息(寄存器、bit偏移等)。

int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
                             struct pinctrl_gpio_range *range,
                             unsigned offset);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
                           struct pinctrl_gpio_range *range,
                           unsigned offset);
int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
                           struct pinctrl_gpio_range *range,
                           unsigned offset,
                            bool input);

2)修改gpio chip的.request、.free、.direction_input、.direction_output等回调函数,让它们调用pinctrl subsystem提供的相关API,如下:

int pinctrl_request_gpio(unsigned gpio) ; 
void pinctrl_free_gpio(unsigned gpio) ;
int pinctrl_gpio_direction_input(unsigned gpio);
int pinctrl_gpio_direction_output(unsigned gpio);  

注2:有些硬件平台,在完成上面步骤1)的时候,可能会遇到一些困扰,例如怎么根据gpio和pin的信息,找到对应的硬件控制信息(寄存器、bit偏移等),这时我们可以灵活处理。例如在本文例子所使用的bubblegum-96平台上,gpio的pinmux功能并没有单独的寄存器控制,而是通过gpio的in或者out功能的使能,覆盖其它的pinmux功能。此时我们可以把硬件配置的操作交给gpio driver,而pinctrl driver只处理管脚的互斥。具体可参考下面patch的改动。

patch:https://github.com/wowotechX/linux/commit/cf4d492855d0619772876bc8494b7e180c6a4232

3. 测试步骤

请参考[3]中的测试。测试结果如下(看到s900_gpio_request_enable中的打印,就说明我们的移植成功了):

/ # mkdir /sys
/ # mount -t sysfs /sys /sys

/ # echo 19 > /sys/class/gpio/export
[   55.136218] owl_pinctrl e01b0000.pinctrl: s900_gpio_request_enable, range(19/52/1), offset 52

/ # echo out > /sys/class/gpio/gpio19/direction
[   86.886343] owl_gpio e01b0000.gpio: offset 19, value 0

/ # echo 1 > /sys/class/gpio/gpio19/value
[  100.223812] owl_gpio e01b0000.gpio: offset 19, value 1

/ # echo 0 > /sys/class/gpio/gpio19/value
[  120.467468] owl_gpio e01b0000.gpio: offset 19, value 0

4. 参考文档

[1] linux内核中的GPIO系统之(4):pinctrl驱动的理解和总结

[2] linux内核中的GPIO系统之(5):gpio subsysem和pinctrl subsystem之间的耦合

[3] X-025-KERNEL-Linux gpio driver的移植之基本功能

[4] X-023-KERNEL-Linux pinctrl driver的移植

[5] Schematics_Bubblegum96.pdf

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

标签: driver GPIO porting pinctrl range

评论:

bigpillow
2017-11-10 10:54
刚写完一套GPIO driver.
当时考虑到不同chip通用性使用了gpiochip_add_pin_range function
现在看看在DTS里面原来这么方便。

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog