gpio-led驱动代码实现

1、设置设备树节点

2、驱动程序 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>

#define DTSLED_CNT    1         /*设备个数*/
#define DTSLED_NAME   "led"     /*设备名字*/



int err;
int temp;	
int gpioled1,gpioled2;/*GPIO号*/

struct led_dev{
	int major;/*主设备号*/
	int minor;/*次设备号*/
	dev_t devid; /*设备号*/
	struct cdev cdev; /*字符设备*/
	struct class *class;/*类 */
	struct device *device; /*设备*/	
	struct device_node *dnode;/*设备树的节点信息*/
};

struct  led_dev ledev;

/*控制灯的亮灭情况*/
static void led_switch(u8 stu){
	switch(stu){
		case 0:{
			gpio_set_value(gpioled1, 1);
			gpio_set_value(gpioled2, 0);
			break;
		}
		case 1:{
			gpio_set_value(gpioled1, 0);
			gpio_set_value(gpioled2, 1);
			break;
		}
		case 2:{
			gpio_set_value(gpioled1, 1);
			gpio_set_value(gpioled2, 1);
			break;
		}
	}
}

/*led_fops的 led_open*/
static int led_open(struct inode *inode, struct file *file)
 {
    return 0;
 }
 
/*led_fops的led_read*/
static ssize_t led_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    return 0;
}

/*led_fops的led_write*/
static ssize_t led_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
 {
	int retvalue;
	
	unsigned char databuf[1];
	printk("led_write\n");
	retvalue=copy_from_user(databuf,buf,len);
	
	if(retvalue < 0){
		printk("kernel write failed!\n");
		return -EFAULT;
	}
	
	led_switch(databuf[0]);
	 
	 
    return 0;
 }

/*led_fops的led_release*/
static int led_release(struct inode *inode, struct file *file)
 {
    return 0;
 }


/*外部控制*/
static const struct file_operations led_fops={
	.owner = THIS_MODULE,
	.read = led_read,
	.write = led_write,
	.open = led_open,
	.release = led_release,
};


/*attribute生产调试节点 led_show*/
static ssize_t led_show(struct device *dev, struct device_attribute *attr, char *buf){
	printk("_show\n");
	
	return 0;
}
/*attribute生产调试节点 led_store*/
static ssize_t led_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){
	
	int regvalue=0;
	printk("_store\n");
	kstrtouint(buf,0,&regvalue);
	
	led_switch(regvalue);
	
	return count;
}


static DEVICE_ATTR(led,0660,led_show,led_store);//这个函数会将第一个参数led补全为dev_attr_led



static const struct of_device_id gpio_led_match[] = {
	{ .compatible = "hello_test", },
	{ },
};
MODULE_DEVICE_TABLE(of, gpio_led_match);

static int gpio_led_probe(struct platform_device * pdev)
{
	int ret = 0;
	printk("hello test probe");
	
	
	
	/*注册字符设备*/
	/*1、申请设备号*/
	ledev.major=0;
	if(ledev.major){/*定义设备号*/
		ledev.devid=MKDEV(ledev.major,0);
		ret=register_chrdev_region(ledev.devid,DTSLED_CNT,DTSLED_NAME);
	}else{/*没有给定设备号*/
		ret = alloc_chrdev_region(&ledev.devid,0,DTSLED_CNT,DTSLED_NAME);
		ledev.major = MAJOR(ledev.devid);
		ledev.minor = MINOR(ledev.devid);
	}
	
	if(ret < 0){
		return -1;
	}
	
	
	/*2、添加字符设备*/
	ledev.cdev.owner = THIS_MODULE;
	cdev_init(&ledev.cdev,&led_fops);//申请空间和简单的初始化,led_fops函数是指向处理与设备实际通信的函数
	ret = cdev_add(&ledev.cdev,ledev.devid,DTSLED_CNT);
	if(ret < 0){
		return -1;
	}
	
	ledev.class = class_create(THIS_MODULE,DTSLED_NAME);//class_create函数动态的创建设备的逻辑类,完成部分字段的初始化,
	//然后添加到Linux的内核中去,效果是创建一个以第二个参数为文件的空文件名
	if(IS_ERR(ledev.class)){
		ret=PTR_ERR(ledev.device);
		return -1;
	}
	
	ledev.device = device_create(ledev.class,NULL,ledev.devid,NULL,DTSLED_NAME);
	//device_create能自动创建设备文件是依赖于udev这个应用程序,设备文件通常放在/dev目录下。
	//使用udev后,在/dev目录下就只包含系统中真正存在的设备。
	if(IS_ERR(ledev.device)){
		ret = PTR_ERR(ledev.device);
		return -1;
	}
	
	
	/*解析设备树节点信息,通过名字*/
	ledev.dnode = of_find_node_by_name(NULL,"hello_test");
	if(ledev.dnode == NULL){
		printk("of_find_node_by_name failed\n!");
		return -1;
	}
	
	
	/*根据设备结点的信息结构体获取gpio编号*/
	gpioled1 = of_get_named_gpio(ledev.dnode,"red-gpios",0);
	if(gpioled1<0){
		printk("of_get_named_gpio failed!\n");
		return -1;
	}
	printk("gpioled1 = %d \n",gpioled1);
	gpioled2 = of_get_named_gpio(ledev.dnode,"green-gpios",0);
	if(gpioled2<0){
		printk("of_get_named_gpio failed!\n");
		return -1;
	}
	printk("gpioled2 = %d \n",gpioled2);
	/*申请GPIO号*/
	err=gpio_request(gpioled1,NULL);
	gpio_request(gpioled2,NULL);
	if(err < 0 )
	{
		printk("gpio_request!\n");
		return -1;
	}
	
	/*设置GPIO方向为输出并默认输出低电平*/
	err=gpio_direction_output(gpioled1,0);
    gpio_direction_output(gpioled2,0);
	if(err<0){
		printk("gpio_direction_output!\n");
		return -1;
	}
	
	/*默认灯打开状况*/
	gpio_set_value(gpioled1,1);
    gpio_set_value(gpioled2,0);
	
	/*attribute生产调试节点*/
	err = device_create_file(&pdev->dev, &dev_attr_led);
	if(err<0){
		printk("device_create_file failed!\n");
		return -1;
	}
	
	return 0;
	
	

}

static void gpio_led_shutdown()
{
	printk("shutdown\n");
}

static struct platform_driver gpio_led_driver={
	.probe		= gpio_led_probe,//探测方法和设备的初始化操作
	.shutdown	= gpio_led_shutdown,
	.driver		= {
		.name	= "hello_test",//设备树节点名称
		
		.of_match_table = gpio_led_match,//定义兼容的驱动属性
	}
};


static int  __init led_init(){
	
	printk("led_init !\n");
	return platform_driver_register(&gpio_led_driver);
}

static void __exit led_exit(){
     printk("led_exit \n!");	
	gpio_set_value(gpioled1,0);
    gpio_set_value(gpioled2,0);
	
	gpio_free(gpioled1);
	gpio_free(gpioled2);
	
	platform_driver_unregister(&gpio_led_driver);
}

module_init(led_init);
module_exit(led_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shakespeare");

3、应用程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char*argv[])
{
	int fd,retvalue;

	char *filename;
	unsigned char databuf[1];

	if(argc < 2){
		printf("Error Usage!\r\n");
		return -1;
	}

//	databuf[0] = atoi(argv[2]);

	filename = argv[1];
	
	fd = open(filename,O_RDWR);

        while(1){
		databuf[0] = 0;
		 retvalue = write(fd,databuf,1);
	         if(retvalue < 0)
		 {
			 printf("LED Control Failed!\r\n");
			 close(fd);
			 return -1;
		 }

		sleep(1);

		databuf[0] = 1;
		retvalue = write(fd,databuf,1);
		if(retvalue < 0)
		{
			printf("LED Control Failed!\r\n");
			close(fd);
			return -1;
		}

		sleep(1);
	}


	close(fd);

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值