芯灵思Sinlinx A64 linux 通过设备树写LED驱动(附参考代码,未测试)
开发平台 芯灵思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驱动(附参考代码,未测试)的更多相关文章
- 芯灵思Sinlinx A64 Linux&qt编译安装
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 前提条件搭建好CentOS环境 ...
- 芯灵思Sinlinx A64开发板 Linux内核等待队列poll ---阻塞与非阻塞
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 阻塞:阻塞调用是指调用结果 ...
- 芯灵思Sinlinx A64开发板Linux内核定时器编程
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 Linux 内核定时器是内 ...
- 芯灵思Sinlinx A64 开发板移植SQLite3
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 首先到 http://ww ...
- 芯灵思Sinlinx A64开发板设置qt程序自启动
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 对于开发板开机启动程序的设置可以这样做通过串口连接开发板 v ...
- Linux 获取设备树源文件(DTS)里描述的资源
Linux 获取设备树源文件(DTS)里的资源 韩大卫@吉林师范大学 在linux使用platform_driver_register() 注册 platform_driver 时, 需要在 plat ...
- Linux 获取设备树源文件(DTS)里的资源【转】
本文转载自:http://blog.csdn.net/keleming1/article/details/51036000 http://www.cnblogs.com/dyllove98/archi ...
- Linux dts 设备树详解(二) 动手编写设备树dts
Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 前言 硬件结构 设备树dts文件 前言 在简单了解概念之后,我们可以开始尝试写一个 ...
- Linux dts 设备树详解(一) 基础知识
Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 1 前言 2 概念 2.1 什么是设备树 dts(device tree)? 2. ...
随机推荐
- jquery实现本地图片上传预览和限流处理
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- java 继承、重载、重写与多态
首先是java 继承.重载和重写的概念 继承: 继承的作用在于代码的复用.由于继承意味着父类的所有方法亦可在子类中使用,所以发给父类的消息亦可发给衍生类.如果Person类中有一个eat方法,那么St ...
- 简单的OO ALV小示例
OO ALV即面向对象ALV,是在屏幕上显示的一种可以自定义大小的ALV.它区别普通ALV的优点是可以多个ALV出现在同一个屏幕,也可以同其他屏幕元素同时出现在同一个屏幕. 示例展示: 1. 进入实用 ...
- Java泛型之自限定类型
在<Java编程思想>中关于泛型的讲解中,提到了自限定类型: class SelfBounded<T extends SelfBounded<T>> 作者说道: 这 ...
- bll
string str = ConfigurationManager.AppSettings["DBName"].ToString(); public Studal ss() { A ...
- 学号 20175223 《Java程序设计》第 6 周学习总结
目录 教材学习内容总结 代码调试中的问题和解决过程 1. 编译运行时,跳过 Scanner.nextLine() 语句. 2. 提示 NullPointerException 错误. [代码托管] 学 ...
- 后台List里的数据传到前台表格和下拉列表为什么不显示
传到前台表格和下拉列表我是用<c:forEach做的,百度了很久,仔仔细细对我的代码没有问题,那么到底是为什么不显示呢?! 找了很久啊,最后发现是我没有引入jstl的标签库!居然是因为这个…… ...
- dos5章
一.用set命令设置自定义变量 显示.设置或删除 cmd.exe 环境变量. SET [variable=[string]]variable 指定环境变量名.string 指定要指派给变量的一系列字符 ...
- c/c++ 栈与队列实现车库的出入与收费
/* 设停车场是一个可停放n辆车的狭长通道,且只有一个大门可供汽车进出.汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列 (大门在最南端,最先到达的第一辆车停放在车场的最北段),若停车厂内 ...
- 两种语言实现设计模式(C++和Java)(一:工厂模式)
本篇开始记录实现设计模式在工作中的两种常见语言上的实现. 本篇介绍最简单的工厂模式. 工厂模式有一种非常形象的描述,建立对象的类就如一个工厂,而需要被建立的对象就是一个个产品:在工厂中加工产品,使用产 ...