/*头文件*/
/*设备个数,名字,状态的宏定义*/
/*映射后的寄存器虚拟地址指针*/
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");
在设备树中添加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");