GPIO驱动是通过GPIOLIB通用架构实现。GPIOLIB是linux下统一管理gpio设备的架构接口,在linux的menuconfig下选择:
----GPIO Support
/SYS/CLASS/GPIO/...(SYSFS INTERFACE)
就可以进行GPIOLIB的统一管理。驱动代码源文件drivers\gpio\xilinx_gpiops.c。
gpiops.c首先注册初始化一个设备xgpiops:
static int__init xgpiops_init(void)
{
returnplatform_driver_register(&xgpiops_driver);
}
subsys_initcall(xgpiops_init);
然后在xgpiops_probe()函数里增加对gpio_chip结构添加,这个结构实际上也是一个抽象的GPIO控制器:
chip =&gpio->chip;
//标签
chip->label= "xgpiops";
//模块指针
chip->owner= THIS_MODULE;
//可选的设备结构
chip->dev= &pdev->dev;
//获取相应偏移脚的值
chip->get= xgpiops_get_value;
//设置相应偏移脚的输出值
chip->set= xgpiops_set_value;
//配置偏移脚为输入引脚
chip->direction_input= xgpiops_dir_in;
//配置偏移脚为输出引脚
chip->direction_output= xgpiops_dir_out;
//未选DEBUGFS,所以不配置
chip->dbg_show= NULL;
//gpio_chip管理的第一个GPIO的编号
chip->base= 0; /* default pin base*/
//gpio_chip管理的GPIO数目
chip->ngpio= 246;
//是否有睡眠功能
chip->can_sleep= 0;
这样配置后,GPIO控制器就根据应用程序的调用语句或者shell的输入命令来对对应的GPIO口进行操作。使用GPIOLIB管理后,多了SYS/CLASS/GPIO文件夹以方便对指定GPIO脚进行操作。参考linux内核文档可知,SYS/CLASS/GPIO有以下三种类型入口:
--用户空间控制GPIO的接口(第一类)
--对应具体的GPIO接口(第二类)
--GPIO控制器(“GPIO_CHIP”实例)(第三类)
默认情况下,SYS/CLASS/GPIO下已经有两类接口:
--export和unexport(第一类):
--export:用户空间通过写入GPIO编号来向内核申请指定GPIO控制权导出到用户空间。
--unexport:和导出效果相反。
--gpiochip0(第三类):申请的gpio控制器信息,“0”指管理的第一个gpio编号,与chip->base值一致。
我们在ZYNQ QEMU(ZYNQ QEMU为了调试方便,把GPIO0~7脚和GPIO54~61依次连接起来,以下实例是用GPIO0和GPIO54作例子)下进行测试,输入命令:
echo 0 > export
echo 54 > export
分别为0号和54号GPIO创建节点。我们会发现在SYS/CLASS/GPIO下会多了两个GPIO接口,这些就是刚才提到的第二类接口:
进入gpio0可以看到:
其中主要的属性是:
--direction:写入“OUT”,设置成输出接口;写入“IN”,设置成输入接口。
--value:读取结果是0或1。如果端口配置成输出,此值可写入,任何非零值都将输出高电平。
--active_low:读取结果0或1。写入任何非零值将反转“value”中读取和写入的值。
继续在ZYNQ QEMU下测试,输入命令:
echo out > gpio0/direction
echo in > gpio54/direction
分别设置gpio0为输出和设置gpio54为输入。
cat gpio54/value
cat gpio0/value
echo 1 > gpio0/value
cat gpio54/velue
输出结果是:
可以看出从GPIO54输出了设定值。如果能直接接硬件通过NFS等手段控制,测试效果更好。
以上可看出,用GPIOLIB统一管理,能在命令行中方便使用指令控制指定的GPIO信号。如果在应用程序中配置操作GPIO,系统也提供了方便的调用手段。查看XILINX提供的测试工程sobel_qt中,查看hwi.c:
voidgpio_reset(int level)
{
// reset TPG
gpio_export(TPG_RST_PIN);
gpio_dir_out(TPG_RST_PIN);
gpio_value(TPG_RST_PIN, level);
gpio_unexport(TPG_RST_PIN);
// reset SOBEL
gpio_export(SOBEL_RST_PIN);
gpio_dir_out(SOBEL_RST_PIN);
gpio_value(SOBEL_RST_PIN, level);
gpio_unexport(SOBEL_RST_PIN);
// set the external clock for the
gpio_export(EXT_SYNC_PIN);
gpio_dir_out(EXT_SYNC_PIN);
gpio_value(EXT_SYNC_PIN, gLiveVideoOn);
gpio_unexport(EXT_SYNC_PIN);
}
以上代码片段实际上是进行一些GPIO脚复位操作。主要函数是:
--gpio_export(unsigned gpio):导出控制权,效果与export命令一样。
--gpio_dir_out(unsigned gpio):指定端口为输出,效果与out命令一样。
--gpio_dir_in(unsigned gpio):指定端口为输入,效果与in命令一样。
--gpio_value(unsigned gpio,unsigned value):指定输出值。
--gpio_unexport(unsignedgpio):解除导出控制权,效果与unexport命令一样。