我是靠谱客的博主 优秀蓝天,最近开发中收集的这篇文章主要介绍Linux下的gpio控制器驱动,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

这里写了一个简单的gpio控制器驱动,用来学习。

#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

static int mgpio_request(struct gpio_chip *chip, unsigned offset)
{
	pr_info("%s %d+%dn", __FUNCTION__,chip->base, offset);
	return 0;
}
void mgpio_free(struct gpio_chip *chip, unsigned offset)
{
	pr_info("%s %d+%dn", __FUNCTION__, chip->base, offset);
}

static int mgpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
	pr_info("%s %d+%dn", __FUNCTION__,chip->base, offset);
	return 0;
}

static int mgpio_direction_output(struct gpio_chip *chip, unsigned offset,
				      int value)
{
	pr_info("%s %d+%d %dn", __FUNCTION__, chip->base, offset, value);
	return 0;
}
static void mgpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
	pr_info("%s %d+%d %dn", __FUNCTION__, chip->base, offset, value);
}

static int mgpio_get(struct gpio_chip *chip, unsigned offset)
{
	pr_info("%s %d+%dn", __FUNCTION__,chip->base, offset);
	return 0;
}

static struct gpio_chip chip= {
	.label = "ap-gpio",
	.request = mgpio_request,
	.free = mgpio_free,
	.direction_input =  mgpio_direction_input,
	.direction_output = mgpio_direction_output,
	.get = mgpio_get,
	.set = mgpio_set,
};

static int __init debug_init(void)
{
	int ret;
	chip.ngpio=256;
	chip.base=0;
	ret=gpiochip_add(&chip);	
	if(ret<0)
		pr_info("gpiochip_add err!n");
	else
		pr_info("gpiochip_add successful!n");
        return ret;
}

static void __exit debug_exit(void)
{
}

module_init(debug_init);
module_exit(debug_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("WWW");

Makefile文件

ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /usr/src/linux-headers-5.0.0-13-generic/
PWD :=$(shell pwd)

modules:  
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
modules_install:  
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install  
clean:  
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order  Module.symvers  
.PHONY: modules modules_install clean  
else  
	obj-m:= gpio.o  
endif

工作原理:为每个gpio分配一个desc,并将具体的gpio_chip控制器加入gpio_chips链表。

struct gpio_desc {
	struct gpio_chip	*chip;
	unsigned long		flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED	0
#define FLAG_IS_OUT	1
#define FLAG_EXPORT	2	/* protected by sysfs_lock */
#define FLAG_SYSFS	3	/* exported via /sys/class/gpio/control */
#define FLAG_ACTIVE_LOW	6	/* value has active low */
#define FLAG_OPEN_DRAIN	7	/* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8	/* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9	/* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED	11	/* GPIO is hogged */

	/* Connection label */
	const char		*label;
	/* Name of the GPIO */
	const char		*name;
};
int gpiochip_add(struct gpio_chip *chip)
{
	unsigned long	flags;
	int		status = 0;
	unsigned	id;
	int		base = chip->base;
	struct gpio_desc *descs;

	descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL);
	
	status = gpiochip_add_to_list(chip);

	for (id = 0; id < chip->ngpio; id++) {
		struct gpio_desc *desc = &descs[id];
		desc->chip = chip;
		desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
	}

	chip->desc = descs;
}
LIST_HEAD(gpio_chips);

static int gpiochip_add_to_list(struct gpio_chip *chip)
{
	struct list_head *pos;
	struct gpio_chip *_chip;
	int err = 0;

	/* find where to insert our chip */
	list_for_each(pos, &gpio_chips) {
		_chip = list_entry(pos, struct gpio_chip, list);
		/* shall we insert before _chip? */
		if (_chip->base >= chip->base + chip->ngpio)
			break;
	}

	/* are we stepping on the chip right before? */
	if (pos != &gpio_chips && pos->prev != &gpio_chips) {
		_chip = list_entry(pos->prev, struct gpio_chip, list);
		if (_chip->base + _chip->ngpio > chip->base) {
			dev_err(chip->dev,
			       "GPIO integer space overlap, cannot add chipn");
			err = -EBUSY;
		}
	}

	if (!err)
		list_add_tail(&chip->list, pos);

	return err;
}

驱动使用gpio时,会先申请gpio,gpio_request会遍历gpio_chips中的每个gpio_chip,找到gpio对应的desc。

struct gpio_desc *gpio_to_desc(unsigned gpio)
{
	struct gpio_chip *chip;
	unsigned long flags;

	spin_lock_irqsave(&gpio_lock, flags);

	list_for_each_entry(chip, &gpio_chips, list) {
		if (chip->base <= gpio && chip->base + chip->ngpio > gpio) {
			spin_unlock_irqrestore(&gpio_lock, flags);
			return &chip->desc[gpio - chip->base];
		}
	}

	spin_unlock_irqrestore(&gpio_lock, flags);

	if (!gpio_is_valid(gpio))
		WARN(1, "invalid GPIO %dn", gpio);

	return NULL;
}
int gpio_request(unsigned gpio, const char *label)
{
	struct gpio_desc *desc = gpio_to_desc(gpio);

	/* Compatibility: assume unavailable "valid" GPIOs will appear later */
	if (!desc && gpio_is_valid(gpio))
		return -EPROBE_DEFER;

	return gpiod_request(desc, label);
}

安装该驱动后,通过echo n >/sys/class/gpio/export来控制具体的gpio,如echo 1 > /sys/class/gpio/export,

可以写int,out,low,high到direction节点

cat value可以查看gpio引脚状态

echo 1/0> value(已设置成输入状态)

查看已申请的gpio引脚状态

最后

以上就是优秀蓝天为你收集整理的Linux下的gpio控制器驱动的全部内容,希望文章能够帮你解决Linux下的gpio控制器驱动所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部