|
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");
|
|