龙芯技术社区
直播中

jf_48561352

未满1年用户 30经验值
擅长:嵌入式技术
私信 关注
[2K系列]

【龙芯2K0300蜂鸟板试用】4 gpio控制key字符驱动

key是最常用的也是最简单的驱动程序,在linux内核当中,应该有现成的配置和驱动,但在龙芯2k0300中没有配置,在此通过自定义的形式,验证此问题

硬件电路

QQ_1724551448310.png

驱动适配

设备树

gpio_key{
		compatible = "lx,gpio-key"; 
		label = "gpiokey";
		gpios = <&gpio 83 GPIO_ACTIVE_LOW>;
		status = "ok";
	};

驱动代码

平台驱动

static const struct of_device_id inputkey_of_match[] = {
    {.compatible = "lx,gpio-key"},
    { }
};



static struct platform_driver lx_input_key_driver = {
    .probe      = lx_input_key_probe,
    .remove     = lx_input_key_remove,
    .driver     = {
        .name   = "inputkey",
        .owner  = THIS_MODULE,
        .of_match_table = inputkey_of_match,
    },
};

probe

主要注册字符设备,创建class/device,并调用key_gpio_init

static int lx_input_key_probe(struct platform_device *dev)
{

	int ret = 0;

	//key_dev.dev_id = MKDEV(key_dev.major,0);
	//ret = register_chrdev_region(key_dev.dev_id,DEVICE_CNT,DEVICE_NAME);

	ret = alloc_chrdev_region(&key_dev.dev_id,0,DEVICE_CNT,DEVICE_NAME);
	if(ret<0)
	{
		pr_err("it cann't alloc chrdev\\\\n");
		goto faile_devid;
	}
	key_dev.major = MAJOR(key_dev.dev_id);
	key_dev.minor = MINOR(key_dev.dev_id);
	pr_info("dev id geted:%d:%d!\\\\n",key_dev.major,key_dev.minor);

	key_dev.cdev.owner = THIS_MODULE;
	cdev_init(&key_dev.cdev,&lx_key_fops); 
	ret = cdev_add(&key_dev.cdev,key_dev.dev_id,DEVICE_CNT);
	if(ret<0){
		pr_err("cdev_add err\\\\r\\\\n");
		goto fail_cdev;
	}
	pr_info("chr dev inited!\\\\r\\\\n");

	key_dev.class = class_create(THIS_MODULE,DEVICE_NAME);
	if(IS_ERR(key_dev.class)){
		pr_info("class err!\\\\r\\\\n");
		ret = PTR_ERR(key_dev.class);
		goto fail_class;
	}
	pr_info("dev class created\\\\r\\\\n");
	
	key_dev.device = device_create(key_dev.class,NULL,key_dev.dev_id,NULL,DEVICE_NAME);
	if(IS_ERR(key_dev.device)){
		pr_info("device err!\\\\r\\\\n");
		ret = PTR_ERR(key_dev.device);
		goto fail_device;
	}
	pr_info("device created!\\\\r\\\\n");

	ret = key_gpio_init(&key_dev);
	if(ret<0){pr_info("key_gpio_init err!\\\\r\\\\n");
		goto fail_device;  
	}
	return ret;

fail_device:
	pr_info("device create err,class destroyed\\\\r\\\\n");
	class_destroy(key_dev.class);
fail_class:
	pr_info("class create err,cdev del\\\\r\\\\n");
	cdev_del(&key_dev.cdev);
fail_cdev:
	pr_info("cdev init err,chrdev register\\\\r\\\\n");
	unregister_chrdev_region(key_dev.dev_id,DEVICE_CNT);
faile_devid:
	pr_info("dev id err\\\\r\\\\n");
	return ret;
}

控制逻辑

key_gpio_init主要完成设备树信息的获取,并注册中断

static int key_gpio_init(struct key_dev *dev)
{
	int ret = 0;

	dev->dev_nd = of_find_node_by_path("/gpio_input");
	if(dev->dev_nd == NULL)
	{
		pr_info("can't find device key\\\\n");
		ret = -EINVAL;
		goto fail_nd;
	}
	pr_info("find device key\\n");


	dev->key_gpio = of_get_named_gpio(dev->dev_nd,"gpios",0);
	if(dev->key_gpio < 0)
	{
		ret = -EINVAL;
		goto fail_gpio;
	}
	pr_info("key gpio = %d",dev->key_gpio);

	ret = gpio_request(dev->key_gpio,"key0");
	if(ret){
		ret = -EBUSY;
		pr_err("IO %d can't request\\\\r\\\\n",dev->key_gpio);
		goto fail_request;
	}
	pr_info("gpio=%d\\\\r\\\\n",dev->key_gpio);
 
	ret = gpio_direction_input(dev->key_gpio);
	if(ret<0){
		ret = -EINVAL;
		goto fail_input;
	}

	key_dev.irq=gpio_to_irq(key_dev.key_gpio);
	request_irq(key_dev.irq, gpio_key_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 
		"gpio-key", &key_dev);

	return 0;
fail_input:
	gpio_free(dev->key_gpio);
fail_request:
	fail_gpio:
	fail_nd:
	return ret; 
}

应用测试

通过select机制,监控按键响应

int main(int argc, char *argv[])
{
	int fd;
	fd_set read_fds;
	char c;
	int ret;

	if (argc < 2) {
		fprintf(stderr, "usage: %s <dev>\\\\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	ret = open(argv[1], O_RDWR);
	if (ret < 0) {
		perror("open");
		exit(EXIT_FAILURE);
	}
	printf("file %s opened\\\\n", argv[1]);
	fd = ret;

	while (1) {
		/* Set up reading file descriptors */
		FD_ZERO(&read_fds);
		FD_SET(STDIN_FILENO, &read_fds);
		FD_SET(fd, &read_fds);

		/* Wait for any data fro our device or stdin */
		ret = select(FD_SETSIZE, &read_fds, NULL, NULL, NULL);
		if (ret < 0) {
			perror("select");
			exit(EXIT_FAILURE);
		}

		if (FD_ISSET(STDIN_FILENO, &read_fds)) {
			ret = read(STDIN_FILENO, &c, 1);
			if (ret < 0) {
				perror("read(STDIN, ...)");
				exit(EXIT_FAILURE);
			}
			printf("got '%c' from stdin!\\\\n", c);
		}
		if (FD_ISSET(fd, &read_fds)) {
			ret = read(fd, &c, 1);
			if (ret < 0) {
				perror("read(fd, ...)");
				exit(EXIT_FAILURE);
			}
			printf("got '%c' from device!\\\\n", c);
			printf("got '%d' from device!\\\\n", c);
		}
	}

	close(fd);

	return 0;
}

验证效果

串口终端安装ko文件
QQ_1724595690934.png

运行应用程序

当按下并弹起,内核驱动打印irq:0和irq:1,用户层打印获取得到的值
QQ_1724595756659.png

更多回帖

发帖
×
20
完善资料,
赚取积分