概述
这里写了一个简单的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控制器驱动所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复