#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
/*myirq={
compatible="hqyj,myirq";
interrupt-parent = <&gpiof>;//指定中断父节点为gpiof
interrupts=<9 0>,<7 0>,<8 0>;//第一个u32表示和中断父节点的联系,第二个表示当前中断的触发方式,填0表示不设置
};*/
struct device_node *dnode;
unsigned int key1_irqno;
struct device_node *dnode;
unsigned int gpiono;
char num = 0;
char kbuf[128];
int major;
struct class *cls;
struct device *dev;
// 定义中断处理函数
irqreturn_t key1_handler(int irq, void *dev)
{
num = (num + 1) % 2;
if (num == 0)
{
// 灭灯
gpio_set_value(gpiono, 0);
}
else
{
// 亮灯
gpio_set_value(gpiono, 1);
}
printk("num=%d\n", num);
return IRQ_HANDLED;
}
// 封裝操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
if (file->f_flags & O_NONBLOCK) // 程序以非阻塞读文件
{
}
else
{
kbuf[0] = num;
copy_to_user(ubuf, kbuf, sizeof(kbuf));
}
return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.release = mycdev_close,
};
static int __init mycdev_init(void)
{
// 解析按键的设备树节点
dnode = of_find_compatible_node(NULL, NULL, "hqyj,myirq");
if (dnode == NULL)
{
printk("解析设备树节点失败\n");
return -ENXIO;
}
printk("解析按键的设备树节点成功\n");
// 根据按键的设备树节点解析按键1的软中断号
key1_irqno = irq_of_parse_and_map(dnode, 0);
if (!key1_irqno)
{
printk("解析按键1的软中断号失败\n");
return -1;
}
printk("解析按键1软中断号成功%d\n", key1_irqno);
// 注册中断
int ret0 = request_irq(key1_irqno, key1_handler, IRQF_TRIGGER_FALLING, "key1", NULL);
if (ret0 < 0)
{
printk("注册中断失败\n");
return -1;
}
printk("注册中断成功\n");
// 注册字符设备驱动
major = register_chrdev(0, "mychrdev", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功major=%d\n", major);
// 向上提交目录
cls = class_create(THIS_MODULE, "mycdev");
if (IS_ERR(cls))
{
printk("向上提交目录信息失败\n");
return -PTR_ERR(cls);
}
printk("向上提交目录信息成功\n");
// 向上提供设备节点
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mycdev0", 0);
if (IS_ERR(dev))
{
printk("向上提交设备节点失败\n");
return -PTR_ERR(cls);
}
printk("向上提交设备节点成功\n");
// 解析LED设备树节点
dnode = of_find_node_by_path("/leds");
if (dnode == NULL)
{
printk("解析设备树节点失败\n");
return -ENXIO;
}
printk("解析设备树节点成功\n");
// 获取GPIO编号
gpiono = of_get_named_gpio(dnode, "led1-gpio", 0);
if (gpiono < 0)
{
printk("gpio编号解析失败\n");
return -ENXIO;
}
printk("解析gpio编号成功%d\n", gpiono);
// 申请gpio编号
int ret;
ret = gpio_request(gpiono, NULL);
if (ret)
{
printk("申请gpio编号失败\n");
return -1;
}
printk("申请gpio编号成功\n");
// 设置为输出模式
gpio_direction_output(gpiono, 0);
return 0;
}
static void __exit mycdev_exit(void)
{
// 注销中断
free_irq(key1_irqno, NULL);
unregister_chrdev(major, "mychrdev");
gpio_free(gpiono);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");