开发平台 芯灵思Sinlinx A64
内存: 1GB 存储: 4GB
开发板交流群 641395230
全志A64设备树结构体
#include //设备树里的每个设备及每个设备子节点都用此结构体描述
struct device_node
{
const char *name;
const char *type;
phandle phandle;
const char *full_name;
struct property *properties; //属性
struct property *deadprops; /* removed properties */
struct device_node *parent; //在设备子节点对象,指向属于的设备对象
struct device_node *child; //在设备对象,指向子节点
struct device_node *sibling; //指向同级的下一个对象.
struct device_node *next; /* next device of same type */ //应是指向device_type是同样的对象
struct device_node *allnext; /* next in list of all nodes */ ...
};
//下面函数用于获取设备树里的设备节点及设备子节点
extern struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
//通过名字查找相应的设备节点
static inline int of_get_child_count(const struct device_node *np);
//获取指定设备的子节点个数
extern struct device_node *of_find_node_by_path(const char *path);
//通过路径来获取设备节点,可用于获取设备子节点
extern struct device_node *of_find_node_by_type(struct device_node *from, const char *type); //通过指定的device_type来获取设备节点
//下面函数用于获取设备节点或设备子节点的属性
static inline int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value)
extern int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value);
extern int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz);
extern int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz);
extern int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz);
extern int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value);
extern int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)
首先增加节点,修改dtsi文件。
vim /lichee/linux-3.10/arch/ARM64/boot/dts/sun50iw1p1-pinctrl.dtsi
gpio = <&pio 1 1 1 1 1 0>;
| | | | | | | |-------------------表示有效电平
| | | | | | |----------------------上下拉, 0关闭功能, 1上拉, 2下拉, 3保留
| | | | | |-------------------------驱动力,电流等级(0 - 3),级别越高,输出电流越大
| | | | |----------------------------gpio功能类型,0输入, 1输出, 6和外部中断,7关闭功能(具体查手册)
| | | |------------------------------pin bank 内偏移(即组内第几个io口).
| | |---------------------------------哪组gpio,PA(0),PB(1),PC(2),PD(3),PE(4),PF(5),PG(6),PH(7),PI(8),PJ(9),PK(10),PL(11)
| |--------------------------------------指向哪个gpio控制器, pio / r_pio(PL组) |-----------------------------------------------------属性名字(随便命名)
驱动代码:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define MY_DEVICE_NAME "my_led_device"
- // 获取到设备树中到节点
- static int gpio = -1;
- int get_irqno_from_node(void)
- {
-
- struct gpio_config config;
- struct device_node *np = of_find_node_by_path("/leds");
- if(np){
- printk("find node okn");
- }
- else{
- printk("find node failedn");
- }
- gpio = of_get_named_gpio_flags(nd, "gpios", i, (enum of_gpio_flags *)&config);// 从设备树中读取gpios的GPIO配置编号和标志
- if(!gpio_is_valid(gpio)){
- //判断该 GPIO 编号是否有效,有效gpio_request 则申请占用该 GPIO。如果初始化过程出错,需要调用 gpio_free 来释放之前申请过且成功的 GPIO
- printk("gpio isn't validn");
- return -1;
- }
- if(gpio_request(gpio, "leds") < 0)
- printk("gpio request failed %dn", gpio);
- gpio_direction_output(gpio, 1); //关灯
-
- return 0;
- }
- static int my_open (struct inode *node, struct file *filp)
- {
- if(gpio)
- {
- printk("open okn");
- }
- else
- {
- return -EINVAL;
- }
- return 0;
- }
- static ssize_t my_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
- {
- unsigned char val;
- copy_from_user(&val, buf, 1);
- printk(" gpl_dat address 0x%xn",gpl_dat);
- if (val)
- {
- gpio_direction_output(gpio, 0); //关灯
- printk("led onn");
- }
- else
- {
- gpio_direction_output(gpio, 1); //关灯
- printk("led offn");
- }
- return 1;
- }
- static const struct file_operations my_led_fops = {
- //step 1 :定义file_operations结构体
- .open = my_open,
- .write = my_write,
- };
- //step 1 :
- static struct class *led_class;
- static struct cdev *pcdev; //定义一个cdev指针
- static dev_t n_dev; //第一个设备号(包含了主和次)
- static int __init led_device_init(void)
- {//step 2 :注册
- int ret = -1;
- pcdev = cdev_alloc();//分配cdev结构空间
- if(pcdev == NULL) {
- printk(KERN_EMERG" cdev_alloc errorn");
- ret = -ENOMEM; /* 分配失败 */
- return ret;
- }
- //2. 动态申请设备号
- ret = alloc_chrdev_region(&n_dev, 0 , 2, MY_DEVICE_NAME);
- if(ret < 0 ) {
- //释放前面成功的资源
- kfree(pcdev); /*释放cdev结构空间 */
- printk(KERN_EMERG"alloc_chrdev_region errorn");
- return ret;
- }
- cdev_init(pcdev, &my_led_fops); //初始化cdev结构 /* 建立cdev和file_operations之间的连接 */
- /*
- 或这样初始化cdev结构
- pcdev->owner = THIS_MODULE;
- pcdev->ops = &my_led_fops;
- */
- ret = cdev_add(pcdev, n_dev, 2) ;// 向内核里面添加一个驱动,注册驱动
- if(ret < 0 ) {
- //释放前面成功的资源
- unregister_chrdev_region(n_dev, 2); /* 释放前面申请的调和号*/
- kfree(pcdev); /* 释放cdev结构空间 */
- printk(KERN_EMERG"alloc_chrdev_region errorn");
- return ret;
- }
- /*自动创建设备节点/dev/SinlinxA64_LED*/
- led_class = class_create(THIS_MODULE, "myled");
- device_create(led_class, NULL, n_dev, NULL, "SinlinxA64_LED");
- get_irqno_from_node();
- printk(KERN_EMERG"cdev okn");
- return 0;
- }
- static void __exit led_device_exit(void)
- { //step 2 :注销
- //注销cdev结构
- cdev_del(pcdev);
- //释放设备号
- unregister_chrdev_region(n_dev, 2); /*起始设备号(主、次) 连续的次设备号数量*/
- //释放cdev结构空间
- kfree(pcdev);
-
- device_destroy(led_class, n_dev);
- class_destroy(led_class);
- gpio_free(gpio);
- printk(KERN_EMERG"cdev_del okn");
- }
- module_init(led_device_init);
- module_exit(led_device_exit);
- MODULE_LICENSE("GPL");
复制代码
参考文章:https://blog.csdn.net/jklinux/article/details/82382066
|