tiny4412 驱动 (13)设备树之keys

本文介绍了一个基于Linux 4.19.27的Tiny4412平台按键驱动实现,通过设备树配置了四个按键,并展示了如何使用设备树获取GPIO资源,注册中断处理程序,以及创建字符设备。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设备树:

keys {
                compatible = "tiny4412,keys";
                tiny4412,key1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
                tiny4412,key2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;
                tiny4412,key3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;
                tiny4412,key4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;
        };

直接上代码,后面再把其他补上。

/*
 * keys-dt.c driver for tiny4412 on linux-4.19.27
*/
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#include <linux/platform_device.h>
#include <linux/slab.h>       //
#include <linux/io.h>

#include <linux/gfp.h>
#include <linux/cdev.h>

#include <linux/uaccess.h> /* copy_from_usr, */
#include <linux/interrupt.h>

struct pri_data
{
	int gpio;
	int irq;
	char name[32];
};


#define DEV_NAME		"keys"

struct pri_dev
{	
	dev_t dev;
	int major;
	char name[32];
	struct class *class;
	struct cdev *cdev;
};


static struct pri_dev *dev = NULL;


const struct file_operations fops = 
{
	.owner = THIS_MODULE,
};

static int chrdev_setup(void)
{
	int ret = 0;
	dev = kmalloc(sizeof(struct pri_dev),GFP_KERNEL);
	if(!dev)
		return -ENOMEM;

	strcpy(dev->name, DEV_NAME);

	ret = alloc_chrdev_region(&dev->dev, 0, 1, dev->name);
	dev->major = MAJOR(dev->dev);
	
	if(ret < 0)
	{
		kfree(dev);
		return ret;
	}

	dev->cdev = cdev_alloc();
	if(!dev->cdev)
	{
		unregister_chrdev_region(dev->dev,1);
		kfree(dev);
		return -EFAULT;
	}
	cdev_init(dev->cdev,&fops);
	dev->cdev->owner = THIS_MODULE;
	dev->cdev->ops = &fops;
	cdev_add(dev->cdev,dev->dev,1);

	dev->class = class_create(THIS_MODULE,dev->name);
	ret = PTR_ERR(dev->class);
	if (IS_ERR(dev->class))
	{
		cdev_del(dev->cdev);
		unregister_chrdev_region(dev->dev,1);
		kfree(dev);
		return -EFAULT;
	}

	device_create(dev->class,NULL,dev->dev,NULL,dev->name,dev);

	return 0;
}

static void chrdev_setdown(void)
{
	device_destroy(dev->class, dev->dev);
	class_destroy(dev->class);
	cdev_del(dev->cdev);
	unregister_chrdev_region(dev->dev,1);
	kfree(dev);
}



irqreturn_t keys_handler(int irq, void *dev_id)
{
	struct pri_data *data = (struct pri_data *)dev_id;
	
	pr_info("%s enters, name : %s gpio : %d irq : %d\n", __func__, data->name,
		data->gpio, data->irq);

	return IRQ_HANDLED;
}


static int keys_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	int ret = 0, gpio = -1, irq = -1;
	int i;
	
	struct pri_data *data = NULL;
	
	pr_info("%s called .\n", __func__);

	if(!dev->of_node){
		dev_err(dev, "no platform found .\n");
		return -EINVAL;
	}

	ret = chrdev_setup();
	if(ret){
		dev_err(dev, "chrdev setup err.\n");
		return -EINVAL;
	}

	data = devm_kmalloc(dev,sizeof(struct pri_data) * 4,GFP_KERNEL);
	if(!data){
		dev_err(dev, "no memory.\n");
		goto err;
	}

	for(i = 0; i < 4; i++){
		sprintf(data[i].name, "tiny4412,key%d", i+1);

		/* get gpio from name */
		gpio = of_get_named_gpio(dev->of_node,data[i].name,0);
		if(gpio < 0){
			dev_err(dev, "of get gpio err.\n");
			goto err1;
		}

		data[i].gpio = gpio;

		irq = gpio_to_irq(gpio);
		if(irq < 0){
			dev_err(dev, "get irq from gpio err.\n");
			goto err1;
		}

		data[i].irq = irq;

		/* request irq */
		ret = devm_request_any_context_irq(dev,data[i].irq,keys_handler,IRQF_TRIGGER_FALLING,
			data[i].name,&data[i]);
		if(ret < 0){
			dev_err(dev, "unable request irq from irq :%d of gpio :%d", irq, gpio);
			goto err1;
		}
	}
	

	return 0;

err1:
	devm_kfree(dev,data);

err:
	chrdev_setdown();
	return -EINVAL;
}
static int keys_remove(struct platform_device *pdev)
{
	pr_info("%s called .\n", __func__);

	chrdev_setdown();

	return 0;
}


const struct of_device_id tiny4412_keys_match_tbl[] = 
{
	{.compatible = "tiny4412,keys"},
	{},
};


static struct platform_driver tiny4412_keys_dt_drv = 
{
	.probe = keys_probe,
	.remove = keys_remove,
	.driver = 
	{
		.owner = THIS_MODULE,
		.name = "keys",
		.of_match_table = tiny4412_keys_match_tbl,
	}
};


static int __init keys_dt_init(void)
{
	int ret = 0;

	ret = platform_driver_register(&tiny4412_keys_dt_drv);
	if(ret)
		printk(KERN_ERR "init demo: probe failed: %d\n", ret);

	return ret;
}

static void __exit keys_dt_exit(void)
{
	platform_driver_unregister(&tiny4412_keys_dt_drv);
}

module_init(keys_dt_init);
module_exit(keys_dt_exit);
MODULE_LICENSE("GPL");

测试结果:

按下按键可以得到log:

可以看出,按键中断能识别,上面没有消抖和异步操作,后面有空补上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值