驱动代码编写
添加中断信息
key {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-key";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_key>;
key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /\* KEY0 \*/
interrupt-parent = <&gpio1>;
interrupts = <18 IRQ_TYPE_EDGE_BOTH>; /\* FALLING RISING \*/
status = "okay";
};
加载驱动失败的原因是因为:
两个节点都使用了 同一个GPIO
原厂驱动代码解析 按键设备树。
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of\_address.h>
#include <linux/of\_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/atomic.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/semaphore.h>
#include <linux/of\_irq.h>
#include <linux/irq.h>
#define IMX6ULIRQ\_NAME "imx6ul"
#define IMX6ULIRQ\_COUNT 1
#define IMX6ULIRQOFF 0 /\* 关灯 \*/
#define IMX6ULIRQON 1 /\* 开灯 \*/
#define KEY\_NUM 1
#define KEY0\_VALUE 0X01
#define INVAKEY 0XFF
/\*按键结构体\*/
struct irq\_keydesc{
int gpio; /\*io编号\*/
int irqnum; /\*中断号\*/
unsigned char value; /\*键值\*/
char name[10]; /\*名字\*/
irqreturn\_t (\*handler)(int ,void \*); /\*中断处理函数\*/
};
struct imx6uirq\_dev {
struct cdev cdev;
struct class \*class;/\*类:为了自动创建节点\*/
struct device \*device;/\*设备:为了自动创建节点\*/
dev\_t devid; //设备号
int major; //主设备号
int minor; //次设备号
struct device\_node \*nd; //设备节点
int led_gpio;
struct irq\_keydesc irqkey[KEY_NUM];
struct timer\_list timer;
atomic\_t keyvalue;
atomic\_t releasekey; //
struct mutex lock;
};
struct imx6uirq\_dev imx6uirq; //imx6uirq设备
static int imx6uirq\_open(struct inode \*inode,struct file \*filp)
{
filp->private_data = &imx6uirq;
return 0;
}
static ssize\_t imx6uirq\_read(struct file \*filp,char __user \*buf,size\_t cnt, loff\_t \*offt)
{
int ret = 0;
unsigned char keyvalue;
unsigned char releasekey;
struct imx6uirq\_dev \*dev = filp->private_data;
keyvalue = atomic\_read(&dev->keyvalue);
releasekey = atomic\_read(&dev->releasekey);
if (releasekey)
{
if (keyvalue & 0x80)
{
keyvalue &= ~0x80;
ret = copy\_to\_user(buf,&keyvalue,sizeof(keyvalue));
}
else{
goto data_error;
}
atomic\_set(&dev->releasekey,0);//按下标志清0
}else{
goto data_error;
}
return ret;
data_error:
return -EINVAL;
}
static ssize\_t imx6uirq\_write(struct file \*filp, const char __user \*buf,size\_t cnt, loff\_t \*offt)
{
//struct imx6uirq\_dev \*dev = (struct imx6uirq\_dev \*)filp->private\_data;
return 0;
}
static int imx6uirq\_release(struct inode \*inode,struct file \*filp)
{
//struct imx6uirq\_dev \*dev = (struct imx6uirq\_dev \*)filp->private\_data;
return 0;
}
static irqreturn\_t key0\_handler(int irq,void \*dev_id)
{
struct imx6uirq\_dev \*dev = dev_id;
#if 0
value = gpio\_get\_value(dev->irqkey[0].gpio);
if (value == 0)
{
printk("key 0 press\r\n");
}
else if (value == 1)
{
printk("key 0 release\r\n");
}
#endif
dev->timer.data = (volatile unsigned long)dev_id;
mod\_timer(&dev->timer,jiffies + msecs\_to\_jiffies(10)); //10ms
return IRQ_HANDLED;
}
/\*定时器处理函数\*/
static void timer\_func(unsigned long arg)
{
int value = 0;
struct imx6uirq\_dev \*dev = (struct imx6uirq\_dev \*)arg;
value = gpio\_get\_value(dev->irqkey[0].gpio);
if (value == 0)
{
atomic\_set(&dev->keyvalue,dev->irqkey[0].value);
printk("key 0 press\r\n");
}
else if (value == 1)
{
atomic\_set(&dev->keyvalue,0x80|(dev->irqkey[0].value));
atomic\_set(&dev->releasekey,1);//完整的释放 按键完成之后写入1
printk("key 0 release\r\n");
}
//重新开启定时器
//mod\_timer(&dev->timer,jiffies + msecs\_to\_jiffies(dev->timerperiod));
}
static int keyio\_init(struct imx6uirq\_dev \*dev)
{
/\*1、按键的初始化\*/
int i = 0;
int ret = 0;
dev->nd = of\_find\_node\_by\_path("/key");
if (dev->nd == NULL)
{
printk("key node not find!\r\n");
return -EINVAL;
}
for(i = 0; i <KEY_NUM;i++){
dev->irqkey[i].gpio = of\_get\_named\_gpio(dev->nd,"key-gpio",i);
if (dev->irqkey[i].gpio < 0) {
printk("can't get key%d\r\n", i);
}
}
for(i = 0; i <KEY_NUM;i++){
// /\*获取按键的IO编号\*/
// dev->irqkey[i].gpio = of\_get\_named\_gpio(dev->nd,"key-gpios",i);
memset(dev->irqkey[i].name,0,sizeof(dev->irqkey[i].name));
sprintf(dev->irqkey[i].name,"KEY%d",i);
gpio\_request(dev->irqkey[i].gpio,dev->irqkey[i].name);
gpio\_direction\_input(dev->irqkey[i].gpio);
dev->irqkey[i].irqnum = gpio\_to\_irq(dev->irqkey[i].gpio);
printk("key%d:gpio=%d, irqnum=%d\r\n",i,dev->irqkey[i].gpio,dev->irqkey[i].irqnum);
//或者
//dev->irqkey[i].irqnum = irq\_of\_parse\_and\_map(dev->nd,i);
}
dev->irqkey[0].handler = key0_handler;
dev->irqkey[0].value = KEY0_VALUE;
/\*2、中断初始化\*/
for(i = 0; i <KEY_NUM;i++){
ret = request\_irq(dev->irqkey[i].irqnum,dev->irqkey[i].handler,
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
dev->irqkey[i].name,&imx6uirq);
if (ret<0)
{
printk("irq request\_irq err");
goto fail_irq;
}
}
/\*3 初始化定时器\*/
init\_timer(&imx6uirq.timer);
//imx6uirq.timer.expires = jiffies + msecs\_to\_jiffies(imx6uirq.timerperiod);
imx6uirq.timer.function = timer_func;
imx6uirq.timer.data = (unsigned long)&imx6uirq;
return 0;
fail_irq:
for(i = 0; i <KEY_NUM;i++)
gpio\_free(dev->irqkey[i].gpio);
return ret;
}
static struct file\_operations imx6uirq_fops = {
.owner = THIS_MODULE,
.write = imx6uirq_write,
.open = imx6uirq_open,
.release = imx6uirq_release,
.read = imx6uirq_read,
};
static int __init imx6uirq\_init(void)
{
int ret = 0;
/\*互斥体初始化\*/
mutex\_init(&imx6uirq.lock);
/\*注册字符设备\*/
imx6uirq.major = 0;
if (imx6uirq.major){
imx6uirq.devid = MKDEV(imx6uirq.major,0);//设备号
ret = register\_chrdev\_region(imx6uirq.devid,IMX6ULIRQ_COUNT,IMX6ULIRQ_NAME);
} else{
ret = alloc\_chrdev\_region(&imx6uirq.devid,0,IMX6ULIRQ_COUNT,IMX6ULIRQ_NAME);
imx6uirq.major = MAJOR(imx6uirq.devid);
imx6uirq.minor = MINOR(imx6uirq.devid);
}printk("led major = %d led minor = %d \r\n",imx6uirq.major,imx6uirq.minor);
if (ret < 0){
goto faile_devid;
}
/\*2、添加字符设备\*/
imx6uirq.cdev.owner = THIS_MODULE;
cdev\_init(&imx6uirq.cdev,&imx6uirq_fops);
ret = cdev\_add(&imx6uirq.cdev,imx6uirq.devid,IMX6ULIRQ_COUNT);
if(ret<0){
goto fail_cdev;
}
/\*3、创建设备类\*/
imx6uirq.class = class\_create(THIS_MODULE,IMX6ULIRQ_NAME);
if(IS\_ERR(imx6uirq.class)){
ret = PTR\_ERR(imx6uirq.class);
printk("can't class\_create \r\n");
goto fail_class;
}
/\*创建设备节点\*/
imx6uirq.device = device\_create(imx6uirq.class,NULL,imx6uirq.devid,NULL,IMX6ULIRQ_NAME);
if(IS\_ERR(imx6uirq.device)){
ret = PTR\_ERR(imx6uirq.device);
printk("can't device\_create \r\n");
goto fail_device;
}
ret = keyio\_init(&imx6uirq);
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/9f1459917377e69268b2907f0046009f.png)
![img](https://img-blog.csdnimg.cn/img_convert/776f47f43245060d59850e59dbb1d819.jpeg)
![img](https://img-blog.csdnimg.cn/img_convert/d28f4c4780144ff3367c5e4293a40659.png)
![img](https://img-blog.csdnimg.cn/img_convert/7e10f89e6200680644e7407500aeedd8.png)
![img](https://img-blog.csdnimg.cn/img_convert/e020062fb60e490d0c4bbbb7c01fd8ae.png)
![img](https://img-blog.csdnimg.cn/img_convert/f96468aea095363f2dd504bcc498341c.png)
![](https://img-blog.csdnimg.cn/img_convert/356bb3ec39d464adb141a4fba4da1304.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
链图片转存中...(img-LIcmf62I-1715757378972)]
[外链图片转存中...(img-HdxNQ6G4-1715757378973)]
[外链图片转存中...(img-eKLYZu0F-1715757378973)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!