Toybrick

新手如何写一个GPIO驱动

samtu

中级会员

积分
383
楼主
发表于 2019-8-5 11:53:19    查看: 9894|回复: 2 | [复制链接]    打印 | 只看该作者
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");

回复

使用道具 举报

niuting99

新手上路

积分
30
沙发
发表于 2019-8-20 08:31:01 | 只看该作者
您好,我想请教一下怎么编译驱动,生成.ko文件
回复

使用道具 举报

坐对群山青

新手上路

积分
24
板凳
发表于 2019-11-1 09:44:06 | 只看该作者
config LEDTEST//此处是C文件的名字
        tristate "hahahahaha!"//这里的名字随便改,他会在 make menuconfig里面的菜单上显示出来

        default m
        help
          this is for ledtest

defaullt y:直接编进内核,default m:编译为驱动模块ko
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表