| 
 | 
 
cd kernel/drivers/ 
1,建立 mkdir ttu文件夹-此文件名随便起,再建立文件 Makefile  
obj-$(CONFIG_LEDTEST)         += ledtest.o  
    CONFIG_后面跟的是xxx.c的XXX名字ledtest 
obj-$是条件编译,当Kconfig有用时,他就编译 
 
2,建立 Kconfig 
config LEDTEST//此处是C文件的名字 
        tristate "hahahahaha!"//这里的名字随便改,他会在 make menuconfig里面的菜单上显示出来 
        help 
          this is for ledtest 
 
3,更改前级的Kconfig,Makefile  
 
4,增加dts 我放在 rk3399pro-toybrick-prod.dtsi 
 
多个GPIO口的申请: 
ledtest{  
        compatible = "samtu,ledtest"; 
        ledgpio1 = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;//GPIO1_B2 
        ledgpio2 = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;//GPIO0_A5 
        ledgpio3 = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;//GPIO0_A6 
        status = "okay"; 
 }; 
 
 
 
 
 
5,建立 ledtest.c 
 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/module.h>  
#include <linux/delay.h> 
#include <linux/gpio.h> 
#ifdef CONFIG_OF 
#include <linux/of.h> 
#include <linux/of_gpio.h> 
#include <linux/of_platform.h> 
#endif 
 
 
#define GPIO_LOW 0 
#define GPIO_HIGH 1 
 
 
/*/只需一个函数即可 
int of_get_named_gpio_flags(struct device_node *np, const char *propname, 
    int index, enum of_gpio_flags *flags); 
 
//返回值为int类型的gpio口. 
//np为设备或设备子节点对象, propname为指定的属性名字, index表示获取属性里的第几个值 
// 其中flags一定得注意,按文档里的说明应就是一个int类型的值,但根本就不能为int参数(会导致kernel panic), 
// 通过阅读内核里的代码得出, flags的参数应为struct gpio_config类型. 定义在下面文件: 
-------------------*/ 
struct gpio_config { 
     u32 gpio;       /* gpio global index, must be unique */ 
     u32     mul_sel;    /* multi sel val: 0 - input, 1 - output... */ 
     u32     pull;       /* pull val: 0 - pull up/down disable, 1 - pull up... */ 
     u32     drv_level;  /* driver level val: 0 - level 0, 1 - level 1... */ 
     u32 data;       /* data val: 0 - low, 1 - high, only vaild when mul_sel is input/output */ 
 }; 
 
 
/* 
 
此处是探针程序的运行 
*/ 
static int samtu_ledtest_probe(struct platform_device *pdev) 
{ 
  int ret = -1; 
  int i; 
  int gpio; 
//char led-str[2][8]; 
//char ledstr[][] ={"ledgpio1","ledgpio2","ledgpio3"}; 
  struct gpio_config flag; 
        struct device_node *ledtest_node = pdev->dev.of_node; 
        printk("---------------------hello this is sam is device,probe-------------------------------\n"); 
        printk("%s-%d: enter\n",__FUNCTION__,__LINE__); 
        //gpio = of_get_named_gpio_flags(ledtest_node,"ledgpiox",0,(enum of_gpio_flags *)&flag);//在DTS里面的gGPIO,想获取哪一个参数民 
for(i=0;i<3;i++){ 
 
        if(i==0){gpio = of_get_named_gpio_flags(ledtest_node,"ledgpio1",0,(enum of_gpio_flags *)&flag);} 
        if(i==1){gpio = of_get_named_gpio_flags(ledtest_node,"ledgpio2",0,(enum of_gpio_flags *)&flag);} 
        if(i==2){gpio = of_get_named_gpio_flags(ledtest_node,"ledgpio3",0,(enum of_gpio_flags *)&flag);} 
        //gpio = of_get_named_gpio_flags(ledtest_node,ledgpio1,0,(enum of_gpio_flags *)&flag);//在DTS里面的gGPIO,想获取哪一个参数民 
        if(!gpio_is_valid(gpio)){ 
          printk("this is invalid gpio i=0=ledgpio1,i=1=ledgpio2,i=2=ledgpio3:%d\n",i); 
         return -1; 
        } 
//        ret=gpio_request(gpio,"samtu-gpio1-3");//GPIO是否申请成功,如果不成功执行下面,成功则跳过下面  后面的显示字符是显示在 cat /sys/kernel/debug/gpio  
         if(i==0){ ret=gpio_request(gpio,"ledgpio1");} 
         if(i==1){ ret=gpio_request(gpio,"ledgpio2");} 
            if(i==2){ ret=gpio_request(gpio,"ledgpio3");} 
         // ret=gpio_request(gpio,ledgpio1);//GPIO是否申请成功,如果不成功执行下面,成功则跳过下面  后面的显示字符是显示在 cat /sys/kernel/debug/gpio  
        if(ret!=0){ 
        gpio_free(gpio); 
         printk("this is invalid gpio i=0=ledgpio1,i=1=ledgpio2,i=2=ledgpio3:%d\n",i); 
        return -EIO; 
        } 
        else{ 
 
        gpio_direction_output(gpio,GPIO_HIGH); 
        /*下面三个是根据不同的IO来设定不同的输出*/ 
        if(i==0){ gpio_set_value(gpio,GPIO_LOW); } 
           if(i==1){ gpio_set_value(gpio,GPIO_LOW); } 
        if(i==2){ gpio_set_value(gpio,GPIO_LOW); } 
 
        gpio_set_value(gpio,GPIO_LOW); 
        printk("--------------------gpio is low ,led is open-------------------------------\n"); 
        printk("%s-%d: exit\n",__FUNCTION__,__LINE__); 
        } 
       //return 0;//return ok 
    } 
   return 0;//return ok 
} 
 
 
static int samtu_ledtest_remove(struct platform_device *pdev) 
        { 
 
         return 0; 
        } 
 
#ifdef CONFIG_OF 
/* 
这个是match DTS相关的地方,.compatible 后面的字符和DTS一样就行 
*/ 
static const struct of_device_id of_samtu_ledtest_match[]={ 
 {.compatible = "samtu,ledtest"}, 
 
}; 
#endif 
/* 
他首先执行的是.probe 
主要的结构体,.probe 探针 
             .remove 移除 
             .driver 驱动 
                 .name  
                 .of_match_table  这个是match DTS相关的地方 
*/ 
static struct platform_driver samtu_ledtest_driver= 
   { 
        .probe   = samtu_ledtest_probe, 
        .remove  = samtu_ledtest_remove, 
        .driver  = { 
           .name = "samtu_ledtest", 
           .owner = THIS_MODULE, 
#ifdef CONFIG_OF 
           .of_match_table = of_samtu_ledtest_match, 
#endif 
        }, 
 
   }; 
 
 
/* 
下面的程序是驱动注册,注册平台驱的结构体, 
static struct platform_driver samtu_ledtest_driver 
*/ 
static int __init ledtest_init(void)//init led test //程序运行此处2 
{ 
   printk(KERN_INFO "Enter %s\n", __FUNCTION__); 
   return platform_driver_register(&samtu_ledtest_driver);//然后由此进注册 
        return 0; 
} 
/* 
下面的程序是退出驱动注册 
 
*/ 
static void __exit ledtest_exit(void)//exit the led test 
{ 
        platform_driver_unregister(&samtu_ledtest_driver); 
        printk("Exit ledtest\n"); 
} 
 
/* 
下面的程序是驱动调用,整个驱动首先调用此处 
*/ 
subsys_initcall(ledtest_init);//程序首先调用此处1 
/* 
下面的程序是驱动调用,整个驱动结束时调用此处 
*/ 
module_exit(ledtest_exit); 
 
MODULE_AUTHOR("samtu <tuzhiquan@126.com>"); 
MODULE_DESCRIPTION("Samtu ledtest"); 
MODULE_LICENSE("GPL"); 
 
 |   
 
 
 
 |