Skip to main content

x2600_GPIO设置驱动能力说明文档

本文档基于x2600平台。展示linux代码中设置io口驱动能力的三种方法(任选其一即可):

1, 调用uboot中封装的gpio的API,设置驱动能力。

2, 以模块驱动的方式封装kernel中gpio的API,配合shell命令来很方便的使用gpio,也可以参考shell命令源码直接调用这些以模块驱动方式加载的封装过的API接口。

3, 直接使用kernel中的api相关接口,或者在对应的板极的dtsi中加相应的属性设置驱动能力。

一 修改驱动能力对波形的影响

  • IO口为PD06, IO口类型为TYPEA,修改驱动能力对应的90MHz波形如下:
驱动能力等级为2,即驱动能力为8mA驱动能力等级为1,即驱动能力为4mA
  • 2.IO口为PD00, IO口类型为TYPEB,修改驱动能力对应的90MHz波形如下:
驱动能力等级为3
  • IO口为PE04, IO口类型为TYPEC, 修改驱动能力对应的90MHz波形如下:
驱动能力等级为0

二 GPIO可设置的驱动能力介绍

​ x2600系列芯片的驱动能力寄存器一共有二组,所有IO口均可设置四种等级的驱动能力,具体参数如下图:

三 uboot中设置驱动能力

3.1 设置驱动能力的例程

​ 例程的路径如下:arch/mips/cpu/xburst2/x2600/soc.c

函数的接口说明如下:

/**
* @brief 设置GPIO口的驱动能力
* @param gpio GPIO端口号,例如:GPIO_PORT_D
* @param value 驱动能力等级,例如:GPIO_DS_LEVEL_0
* @param pins GPIO引脚,例如:0x3f << 6
**/
void gpio_set_driver_strength(enum gpio_port gpio, int value, unsigned int pins)

3.2 可配置的驱动能力等级

代码路径为: arch/mips/include/asm/arch-x2600/gpio.h

3.3 函数接口说明

​ 函数具体实现位于:drivers/gpio/jz_gpio_common.c

四 模块驱动中设置驱动能力

在模块驱动下设置驱动能力可采用以下方法(任选其一即可):

  • 使用cmd_gpio 命令动态设置驱动能力,便于调试;
  • 直接调用模块驱动中的设置驱动能力的API

4.1 iconfig配置

4.2 使用cmd_gpio工具命令设置驱动能力

确保加载了soc_gpio.ko驱动,如果/dev目录下没有gpio设备,表示gpio驱动未加载或者未初始化成功。

4.2.1 GPIO SHELL命令详解

cmd_gpio set_strength  <GPIO> <VALUE>
功能:设置io口的驱动能力
参数: GPIO //IO口的名字
VALUE //IO的驱动能力等级
example: cmd_gpio set_strength PD06 1
cmd_gpio get_strength  <GPIO>
功能:获取io口的驱动能力
参数: GPIO //IO口的名字
example:
cmd_gpio get_strength PD06

4.2.2 具体例子

本例展示运用shell命令调整IO口的驱动能力,以PD06为例,默认的驱动等级为2,具体案例如下:

cmd_gpio get_strength PD06  //获取PD06的驱动能力等级
输出结果:
2 //表示此时PD06的驱动能力等级为2
cmd_gpio set_strength PD06 1 //将PD06的驱动能力设置为1
输出结果:
无任何输出
cmd_gpio get_strength PD06  //获取PD06的驱动能力等级
输出结果:
1 //表示此时PD06的驱动能力等级为1

gpio shell源码位置:

libhardware2\src\cmds\gpio_main.c

4.3 调用模块驱动API设置驱动能力

4.3.1 API详细介绍

使用gpio接口需要包含头文件# include <libhardware2/gpio.h>

具体的代码实现对应的文件路径为module_driver目录下:soc/x2600/gpio/gpio.c

int gpio_open(void)
功能:获取gpio设备操作句柄
参数:

返回值:
成功:gpio设备句柄
失败:负数
int gpio_close(int fd)
功能:关闭gpio设备句柄
参数:
fd //gpio设备句柄,由gpio_open()函数获得
返回值:
成功:0
失败:负数
int gpio_set_strength(int fd, const char *gpio, int value);
功能:设置gpio的驱动能力
参数:
fd //gpio设备句柄,由gpio_open()函数获得
gpio //描述对应的gpio引脚,如"PD06"
value //驱动能力等级值
返回值:
成功: 0
失败: 负数
int gpio_get_strength(int fd, const char *gpio);
功能:获取gpio的驱动能力
参数:
fd //gpio设备句柄,由gpio_open()函数获得
gpio //描述对应的gpio引脚,如"PD06"
返回值:
成功:驱动能力等级值
失败:负数

4.3.2 具体例子

本例展示运用接口实现调整x2600的gpio口的驱动能力等级,具体案例如下:

int mian(int argc, char *argv[])
{
int fd, ret;
int value = 1; //设置的驱动能力等级
char *gpio = "PD06"; //要设置的引脚名

fd = gpio_open(); //打开gpio
if (fd < 0) {
fprintf(stderr, "failed to open device\n");
exit(-1);
}

ret = gpio_get_strength(fd, gpio); //得到gpio的驱动能力等级
if (!ret)
fprintf(stderr, "the strength level of %s is %d\n", gpio, ret);

ret = gpio_set_strength(fd, gpio, value); //设置gpio驱动能力等级,此处设置为1
if (ret)
fprintf(stderr, "failed to set strength level\n");

ret = gpio_get_strength(fd, gpio); //得到gpio驱动能力等级,可以比较一下是否与设置一致
if (!ret)
fprintf(stderr, "the strength level of %s is %d\n", gpio, ret);

gpio_close(fd); //关闭gpio
}
运行代码后串口的打印如下:
# the strength level of PD06 is 2
# the strength level of PD06 is 1

五 在kernel中设置驱动能力

​ 在kernel中设置驱动能力等级可采用以下方法(任选其一即可):

  • 在dts中设置驱动能力,由pinctrl进行解析并配置,代码路径为:kernel/module_drivers/drivers/pinctrl/pinctrl-ingenic.c。
  • 直接调用kernel中设置驱动能力的函数接口。

5.1 在dts中设置驱动能力

由于dts中gpio的配置有两种情况,⼀是控制器的io,在xxx-pinctrl.dtsi的pinctrl节点下,通过pinmux进⾏解析,⼆是普通io,在控制器节点对应的驱动,通过解析属性进⾏设置。

5.1.1 在对应板极的dtsi中设置驱动能力

直接在xxx-pinctrl.dtsi的对应控制器节点下添加"ingenic,pincfg"属性,就可以设置pin脚的属性。

例如:以下例子即是将PD00-PD05的驱动能力等级设置为1

注:

  • ingenic,pincfg 形式为 <io组 开始的io号 结束的io号 属性>
  • PINCTL_CFG_DRIVE_STRENGTH的定义位于include/dt-bindings/pinctrl/ingenicpinctrl.h,包装的格式为PINCFG_PACK(PINCTL_CFG_DRIVE_STRENGTH, 1)

5.1.2 在对于板极的dts的对于驱动下设置驱动能力

定义某一个io口的驱动能力,例如某个屏幕的power引脚,可以在对应的控制节点下添加属性,在 对应驱动中通过of_get_named_gpio_flags解析这个属性即可设置:

例如:将rst-gpio对应的IO口的驱动能力设置为1

panel_ma0060 {
compatible = "ingenic,ma0060";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&smart_lcd_pb_te>;
ingenic,vdd-en-gpio = <&gpc 3 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpc 4 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS INGENIC_GPIO_DS_1>;
ingenic,oled-gpio = <&gpc 5 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
ingenic,lcd-pwm-gpio = <&gpc 1 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
ingenic,swire-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
port {
panel_ma0060_ep: endpoint {
remote-endpoint = <&dpu_out_ep>;
};
};
};

驱动能力能设置的等级如下, 代码位于include/dt-bindings/pinctrl/ingenic-pinctrl.h

5.2 调用kernel中的GPIO的API设置驱动能力

5.2.1 申请与释放gpio

int gpio_request(unsigned gpio, const char *label)
功能:申请gpio
参数:
gpio //gpio引脚
label //描述gpio引脚
返回值:
成功:0
失败:负数
void gpio_free(unsigned gpio)
功能:注销gpio
参数:
gpio //gpio引脚
返回值:

5.2.2 获取与设置gpio驱动能力等级

函数的具体实现位于kernel目录下的此路径:arch/mips/xburst2/soc-x2600/gpio.c

int jzgpio_set_strength(int port, int value, unsigned long pin)
功能:设置gpio的驱动能力
参数:
port //gpio引脚组别
value //驱动能力等级
pin //gpio引脚
返回值:
成功: 0
失败: 负数
int jzgpio_get_strength(int port, int *value, unsigned long pin)
功能:获取gpio的驱动能力等级
参数:
port //gpio引脚组别
value //指向驱动能力值的指针
pin //gpio引脚
返回值:
成功: 0
失败: 负数

5.2.3 具体例子

示例代码是将 PD(06)的驱动能力等级由2调整为1, 并在调整之前打印当前 PD(06) 驱动能力等级,在设置之后打印 PD(06)驱动能力等级,具体代码如下:

#include <linux/module.h>
#include <linux/init.h>
#include <soc/gpio.h> //其包含将GPIO_PD(06)转换为数字'102'的封装函数
#include <linux/delay.h> //包含延时函数
#include <linux/gpio.h> //包含gpio相关API

void gpio_test(void) //初始情况下PD06的驱动能力值为2,调整驱动能力为1
{
int val;
int test_gpio = GPIO_PD(06); //设置的GPIO为PD06
int port, pin;
printk(KERN_ERR "start test\n"); //开始测试

gpio_request(test_gpio, "test gpio"); //申请gpio
port = test_gpio / 32; //gpio引脚组别
pin = test_gpio % 32; //gpio引脚

jzgpio_get_strength(port, &val, pin); //获取当前的gpio驱动能力值
printk(KERN_ERR "the strength level of %d is %d \n", test_gpio, val); //打印驱动能力值

val = 1;
jzgpio_set_strength(port, val, pin); //设置gpio驱动能力值为1

val = 0; //将val值清零
jzgpio_get_strength(port, &val, pin); //获取当前的gpio驱动能力值
printk(KERN_ERR "the strength level of %d is %d \n", test_gpio, val); //打印驱动能力值,判断是否与设置的值相同

gpio_free(test_gpio); //释放申请的gpio
}

static int __init vendor_init(void)
{
printk(KERN_INFO "vendor_init test init\n");
gpio_test();
return 0;
}

static void __exit vendor_exit(void)
{
printk(KERN_INFO "vendor_exit test exit\n");
}

module_init(vendor_init);
module_exit(vendor_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhongwan");
MODULE_DESCRIPTION("vendor test");

运行此段代码之后,串口中的打印如下:

# start test
# the strength level of 102 is 2
# the strength level of 102 is 1