楼主在这边给你们介绍下如何使用PopMetal的GPIO。先讲过程,再讲原理吧,php
该驱动须要涉及到的知识点:1,DTS设备树的做用,2,platform虚拟总线驱动的编写。html
第一步,添加DTS节点node
在/kernel/arch/arm/boot/dts/rockchip.dts下添加以下内容。linux
下图rockchip-leds-gpio这部分的内容,修改保存,ios
第二步,在kernel/drivers下建立个LED文件夹,而后加入以下几个文件驱动文件leds.c,Makefile和Kconfig.以下图函数
源码:spa
/***********************************************************************************orm
* driver for led0htm
* blog
**********************************************************************************/
#include <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/of_platform.h>
static int leds_probe(struct platform_device *pdev)
{ int ret =-1
int i
int led
enum of_gpio_flags flag
struct device_node *led_node = pdev->dev.of_node
led = of_get_named_gpio_flags(led_node,"led-gpios",0,&flag)
printk("get gpio id successful\n")
if(!gpio_is_valid(led)){
printk("invalid led-gpios: %d\n",led)
return -1
}
if(gpio_request(led,"led_gpio")){
printk("led gpio request failed!\n")
return ret
}
gpio_direction_output(led,1)
for(i=0 i < 10 i++)
{
gpio_set_value(led,1)
mdelay(500)
gpio_set_value(led,0)
mdelay(500)
printk("it's %d\n",i)
}
return 0
}
static int leds_remove(struct platform_device *pdev)
{
return 0
}
static struct of_device_id leds_of_match[] = {
{ .compatible = "rockchip-leds-gpio" },
{ }
}
MODULE_DEVICE_TABLE(of, leds_of_match)
static struct platform_driver leds_driver = {
.driver = {
.name = "leds-drivers",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(leds_of_match),
},
.probe = leds_probe,
.remove = leds_remove,
};
/*static int __init leds_init(void)
{
printk(KERN_INFO "Enter %s\n", __FUNCTION__)
return platform_driver_register(&leds_driver)
return 0
}
static void __exit leds_exit(void)
{
platform_driver_unregister(&leds_driver)
printk("close leds\n")
}*/module_platform_driver(leds_driver)
module_platform_driver(leds_driver)
MODULE_DESCRIPTION("leds Driver")
MODULE_LICENSE("GPL")
MODULE_ALIAS("platform:leds-drivers")
/***********************************************************************************
* driver for led0
*
**********************************************************************************/
Kconfig:
Makefile:
第三步,修改drivers下的Kconfig和Makefile,修改内容以下
在Kconfig末尾添加:source “drivers/led/Kconfig”
在Makefile末尾添加: obj-$(CONFIG_LED0_TEST) +=led/
第四步,编译新的kernel与resource并烧写进板子里,
而后DTS中定义的引脚就会按照驱动的内容,进行高低电平的变化。
须要源码可下载: led.zip
好了,如今咱们来介绍下原理,首先是DTS,和另外一块开发板PX2不同,PopMetal并无写相应的mach-*****文件,而是经过设备树的方式获取引脚的编号,设备树的引入可减小了内核为支持新硬件而须要的改变,提升代码重用,加速了Linux支持包的开发,使得单个内核镜像能支持多个系统。简单来讲,它就是给内核的一个参数,这些参数会启动相应的驱动,这样参数不同,内核源码支持的系统就不同。
而在这里咱们要清楚的是咱们要用相应的引脚就必须建立相应的节点,而且赋上一些参数。
而驱动又是怎么识别到这些参数的呢?这里咱们先讲讲platform虚拟总线驱动,这个总线跟IIC,SPI等总线不同,是由内核虚拟出来的,咱们就以上面的代码为例,给你们讲讲他是怎么工做的,
首先这个驱动的核心是:
static struct platform_driver leds_driver = {
.driver = {
.name = "leds-drivers",//驱动名
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(leds_of_match),//匹配设备树
},
.probe = leds_probe,//探测函数,检测硬件上是否存在设备,检测到便执行
.remove = leds_remove,//移除函数,硬件移除时,执行
};
在这里咱们只给部份内容赋予了值,自己这个结构体还有别的子项,须要了解的同窗能够在这编博客看看:http://blog.sina.com.cn/s/blog_53c733350100zdav.html
在这个结构体中,咱们就是经过.of_match_table = of_match_ptr(leds_of_match),来匹配设备树上的参数,而即系统会根据设备树种定义的compatible参数比较驱动中的leds_of_match中定义的 .compatible 参数,
来为参数找到相应的驱动,而定义的probe和remove函数则是对探测到设备作出反应,及移除设备时作出反应,而module_platform_driver(leds_driver)是将驱动挂到总线上去,
如今咱们看看probe是怎么获取到GPIO的值的,其中它的主要函数以下:
struct device_node *led_node = pdev->dev.of_node
led = of_get_named_gpio_flags(led_node,"led-gpios",0,&flag)
功能就是将led_node节点上的led-gpios的值取下,而咱们以前在rockchip.dts中队led-gpios的定义以下:
led-gpios=&GPIO6 GPIO_A6 GPIO_ACTIVE_LOW,意思就是选择引脚gpio6_a6,且该引脚低电平有效。
上面这句赋值便已经将引脚的编号赋给了led-gpios,故接下来咱们就能够用GPIO_requset_one GPIO_set_value,等函数去操做这个GPIO了,像gpio_set_value(led-gpios,1)将该引脚设置为高电平。
固然这些操做只是相对于引脚没复用的GPIO口,引脚若是有复用功能,咱们还得进行一些别的操做把引脚的功能选好。