开发平台 芯灵思Sinlinx A64

内存: 1GB 存储: 4GB

详细参数 https://m.tb.cn/h.3wMaSKm

开发板交流群 641395230

全志A64设备树结构体

#include <linux/of.h> //设备树里的每个设备及每个设备子节点都用此结构体描述

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

驱动代码:

    #include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/sys_config.h> #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 ok\n");
}
else{
printk("find node failed\n");
} 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 valid\n");
return -1;
}
if(gpio_request(gpio, "leds") < 0)
printk("gpio request failed %d\n", gpio);
gpio_direction_output(gpio, 1); //关灯 return 0; } static int my_open (struct inode *node, struct file *filp)
{
if(gpio)
{
printk("open ok\n");
}
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%x\n",gpl_dat);
if (val)
{
gpio_direction_output(gpio, 0); //关灯
printk("led on\n");
}
else
{
gpio_direction_output(gpio, 1); //关灯
printk("led off\n");
} 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 error\n");
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 error\n");
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 error\n");
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 ok\n");
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 ok\n");
} module_init(led_device_init);
module_exit(led_device_exit);
MODULE_LICENSE("GPL");

参考文章:https://blog.csdn.net/jklinux/article/details/82382066

芯灵思Sinlinx A64 linux 通过设备树写LED驱动(附参考代码,未测试)的更多相关文章

  1. 芯灵思Sinlinx A64 Linux&qt编译安装

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 前提条件搭建好CentOS环境 ...

  2. 芯灵思Sinlinx A64开发板 Linux内核等待队列poll ---阻塞与非阻塞

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 阻塞:阻塞调用是指调用结果 ...

  3. 芯灵思Sinlinx A64开发板Linux内核定时器编程

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 Linux 内核定时器是内 ...

  4. 芯灵思Sinlinx A64 开发板移植SQLite3

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 首先到 http://ww ...

  5. 芯灵思Sinlinx A64开发板设置qt程序自启动

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 对于开发板开机启动程序的设置可以这样做通过串口连接开发板 v ...

  6. Linux 获取设备树源文件(DTS)里描述的资源

    Linux 获取设备树源文件(DTS)里的资源 韩大卫@吉林师范大学 在linux使用platform_driver_register() 注册 platform_driver 时, 需要在 plat ...

  7. Linux 获取设备树源文件(DTS)里的资源【转】

    本文转载自:http://blog.csdn.net/keleming1/article/details/51036000 http://www.cnblogs.com/dyllove98/archi ...

  8. Linux dts 设备树详解(二) 动手编写设备树dts

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 前言 硬件结构 设备树dts文件 前言 在简单了解概念之后,我们可以开始尝试写一个 ...

  9. Linux dts 设备树详解(一) 基础知识

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 1 前言 2 概念 2.1 什么是设备树 dts(device tree)? 2. ...

随机推荐

  1. C# 索引和长度必须引用该字符串内的位置 LENGTH

    今天遇到了 索引和长度必须引用该字符串内的位置 的问题. 原因是实用 Substring 对字符串进行了前五位的截取,但是忽略了字符串本身不足五位的情况. 如果不足五位,直接将整个字符串赋值过来,添加 ...

  2. Vue源码之 Vue的生命周期

    天地初开就是new Vue(options),里面就一句话 this._init(options); (Vue.prototype.init 的赋值在initMixin(Vue)方法里) _init方 ...

  3. DAY2:数据类型Python3.6

    数字 1.int(整型) 2. long(长整型) 3.float(浮点型) 4.complex(复数)  布尔值 1.真或假 1或0表示 字符串 知识补充 字符串转二进制 mes = "北 ...

  4. Java - Java入门(2-1am)

    第一讲.Java入门 1. 计算机语言是人和计算机进行交互的一种工具,人们通过使用计算机语言编写程序来向计算机施令,计算机则执行程序,并把结果输出给用户. 2. 机器语言:由0.1序列构成的指令码组成 ...

  5. Thymeleaf中href与 th:href的区别

    语法格式如下: <a th:href="@{/channel/page/add}">添加渠道 </a> <a href="/channel/ ...

  6. 微信小程序(mpvue)—解决视频播放bug的一种方式

    // 第一页 <div @click="play(video.src, video.width, video.height)"></div> methods ...

  7. swoole架构分析

    swoole的进程/线程结构 结构图如下: swoole主要由Master进程(主进程)和Manager进程配合使用完成其功能. Master进程 是一个多线程的程序.其中有一组很重要的线程,称之为R ...

  8. js 回调函数理解

    function A(callback) { console.log('我是主函数'); setTimeout(function () { callback("我是主函数传出的") ...

  9. ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一)

    前言: 第一次接触ABP的项目是在2018年6月份,但是当时没有深入具体的研究,而今天因为工作的需要,需要学习.了解这个框架,在时隔半年之后,今天重新下载了这个项目,虽然在园子里有很多前辈们写的这类的 ...

  10. Java学习笔记(5)

    齿状二维数组的声明及使用 或者 int[][] triangleArray = new int[5][]; triangleArray[0] = new int[5]; triangleArray[1 ...