嵌入式Linux设备树下字符驱动编写框架的总结

Step1:在dts中添加设备节点

  

Step2:驱动框架

/*头文件*/
/*设备个数,名字,状态的宏定义*/
/*映射后的寄存器虚拟地址指针*/
static void __iomem *XXX;
/*设备结构体*/
struct XXX_dev {
	dev_t devid;             /*设备号*/
	struct cdev cdev;        /*字符设备*/
	struct class *class;     /*用于自动创建节点的类*/
	int major;               /*主设备号*/
	int minor;               /*次设备号*/
	struct device_node *nd;  /*设备节点*/
}
struct XXX_dev XXX;          /*设备*/

/*设备相关操作定义*/
switch;open;read;write;release;
static int XXX_open(struct inode *inode, struct file*filp) {
	filp->private_data = &XXX;   /*设置私有数据*/
	return 0;
}

/*设备操作函数*/
static struct file_operations XXX_fops = {
	.owner = THIS_MODULE;
	.open = XXX_open;
	.read .....
};

/*驱动入口函数*/
static int __init XXX_init(void) {
	/*使用OF函数获取设备树中的属性数据*/
	/*地址映射*/
	虚拟地址指针 = of_iomap(XXX.nd, x);    /*x是在dts中reg组数的索引,reg中起始地址&长度为一组*/
	/*IO,时钟等配置*/
	
	/*注册字符设备驱动*/
	/*1.创建设备号*/
	if (XXX.major) {                                          /*已定义设备号-注册*/
		XXX.devid = MKDEV(XXX.major, 0);
		register_chrdev_region(XXX.devid, 设备数, 设备名);
	} else {                                                  /*未定义设备号-申请*/
		alloc_chrdev_region(&XXX.devid, 0, 设备数, 设备名);
		XXX.major = MAJOR(XXX.devid);
		XXX.minor = MINOR(XXX.devid);
	}
	printk("XXX major=%d, minor=%d\r\n", XXX.major, XXX.minor);
	/*2.初始化并添加cdev*/
	XXX.cdev.owner = THIS_MODULE;
	cdev_init(&XXX.cdev, &XXX_fops);
	cdev_add(&XXX.cdev, XXX.devid, 设备个数);
	/*3.自动创建设备节点*/
	/*3.1 创建类*/
	XXX.class = class_create(THIS_MODULE, 设备名);
	if (IS_ERR(XXX.class)) {
		return PTR_ERR(XXX.class);
	}
	/*3.2 创建设备*/
	XXX.device = device_create(XXX.class, NULL, XXX.devid, NULL, 设备名);
	if (IS_ERR(XXX.device)) {
		return PTR_ERR(XXX.device);
	}
	return 0;
}

/*驱动出口函数*/
static int __exit XXX_exit(void) {
	/*取消映射*/
	iounmap();
	/*注销字符设备驱动*/
	cdev_del(&XXX.cdev);
	unregister_chrdev_region(XXX.devid, 设备数);
	/*删除设备节点*/
	device_destory(XXX.class, XXX.devid);
	class_destory(XXX.class);
}

module_init(XXX_init);
module_exit(XXX_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("finches");

Step3:引入pinctrl和gpio子系统的驱动框架

在设备树中添加pinctrl节点模板–如何在设备树中添加某个外设PIN信息:
假设一个test设备,使用了GPIO1_IO00这个PIN的GPIO功能。
①创建对应节点:
同一个外设的PIN都放在一个节点中,打开对应的dts,在iomuxc节点中imx6ul-evk子节点下添加pinctrl_test节点。
②添加"fsl,pins"属性:
I.MX系列的SOC,pinctrl驱动程序通过读取该属性值来获取PIN配置信息。
③添加PIN配置信息:

pinctrl_test: testgrp {
	fsl,pins = <
		MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具体设置值*/
	>;
};

设备树中添加gpio节点模板:
①在根节点下创建test设备节点。
②添加pinctrl信息,表示test设备的PIN信息在pincttrl_test节点中。
③添加GPIO属性信息。

test {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_test>;
	gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
};

框架:

/*头文件*/
/*设备个数,名字,状态的宏定义*/
/*设备结构体*/
struct XXX_dev {
	dev_t devid;             /*设备号*/
	struct cdev cdev;        /*字符设备*/
	struct class *class;     /*用于自动创建节点的类*/
	int major;               /*主设备号*/
	int minor;               /*次设备号*/
	struct device_node *nd;  /*设备节点*/
	int xxx_gpio;			 /*xxx设备使用的GPIO编号*/
}
struct XXX_dev XXX;          /*设备*/

/*设备相关操作定义*/
open;read;write;release;
//需要用到gpio子系统的API
static int XXX_open(struct inode *inode, struct file*filp) {
	filp->private_data = &XXX;   /*设置私有数据*/
	return 0;
}

/*设备操作函数*/
static struct file_operations XXX_fops = {
	.owner = THIS_MODULE;
	.open = XXX_open;
	.read .....
};

/*驱动入口函数*/
static int __init XXX_init(void) {
	//1.获取设备节点
	xxx.nd = of_find_node_by_path("/xxx");   //设备节点
	//2.获取设备树中的gpio属性,得到设备使用的GPIO编号
	xxx.xxx_gpio = of_get_named_gpio(xxx.nd, "xxx-gpio", 0);
	//3.设置GPIO,设备初始电平
	ret = gpio_direction_output(xxx.xxx_gpio, 1);
	
	/*注册字符设备驱动*/
	/*1.创建设备号*/
	if (XXX.major) {                                          /*已定义设备号-注册*/
		XXX.devid = MKDEV(XXX.major, 0);
		register_chrdev_region(XXX.devid, 设备数, 设备名);
	} else {                                                  /*未定义设备号-申请*/
		alloc_chrdev_region(&XXX.devid, 0, 设备数, 设备名);
		XXX.major = MAJOR(XXX.devid);
		XXX.minor = MINOR(XXX.devid);
	}
	printk("XXX major=%d, minor=%d\r\n", XXX.major, XXX.minor);
	/*2.初始化并添加cdev*/
	XXX.cdev.owner = THIS_MODULE;
	cdev_init(&XXX.cdev, &XXX_fops);
	cdev_add(&XXX.cdev, XXX.devid, 设备个数);
	/*3.自动创建设备节点*/
	/*3.1 创建类*/
	XXX.class = class_create(THIS_MODULE, 设备名);
	if (IS_ERR(XXX.class)) {
		return PTR_ERR(XXX.class);
	}
	/*3.2 创建设备*/
	XXX.device = device_create(XXX.class, NULL, XXX.devid, NULL, 设备名);
	if (IS_ERR(XXX.device)) {
		return PTR_ERR(XXX.device);
	}
	return 0;
}

/*驱动出口函数*/
static int __exit XXX_exit(void) {
	/*注销字符设备驱动*/
	cdev_del(&XXX.cdev);
	unregister_chrdev_region(XXX.devid, 设备数);
	/*删除设备节点*/
	device_destory(XXX.class, XXX.devid);
	class_destory(XXX.class);
}

module_init(XXX_init);
module_exit(XXX_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("finches");

你可能感兴趣的:(嵌入式,linux,驱动开发)