linux gpio中断

最近用到gpio中断,gpio中断也是嵌入式系统用的比较多的。

对于GPIO操作 linux 有一套标准的 API,set value、get value之类的,当然也有关于中断的。


关于中断的就是:

static inline int gpio_to_irq(unsigned int gpio)
{
	return __gpio_to_irq(gpio);
}


1 使用gpio中断


在linux模块中使用gpio中断的步骤通常如下


1)实现中断处理函数。

static irqreturn_t myIntHandler(int irq, void *dev_id)
{
	printk("Interrupt IN\n");
	return IRQ_HANDLED
}

2)初始化函数

int xxx_init()
{

	int ret, irqno;
	ret = gpio_request(gpioNo, "mygpiopin");
	if(ret){
		printk("irq pin request io failed.\n");
		return -1;
	}

	irqno= gpio_to_irq(gpioNo);


	ret = request_irq(irqno,myIntHandler , RQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "myinterrupt", NULL); 
	if(ret) {
		printk(KERN_ERR "can not get irq\n");
		return ret;
	} 
}
就两个函数:
gpio_request  通常用来检测这个gpio是否可用,是否已经在使用了。

gpio_to_irq 转换gpio编号到对应irq号。

之后就是熟悉的request_irq

有时候还会加一个gpio_is_valid,判断一下gpioNo是否合理,通常自己察看芯片手册填入正确gpio number,不需要再再在这里判断一下。

2,gpio中断API的实现过程

简单看一下。

int gpio_request(unsigned gpio, const char *label)
{
	return gpiod_request(gpio_to_desc(gpio), label);
}

先看参数
gpio_to_desc(gpio)

都在gpiolib.c中

static struct gpio_desc *gpio_to_desc(unsigned gpio)
{
	if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
		return NULL;
	else
		return &gpio_desc[gpio];
}


这里有个全局的数组,看样子是每一个gpio都在这个数组里有这么一项,这个结构体如下

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_TRIG_FALL	4	/* trigger on falling edge */
#define FLAG_TRIG_RISE	5	/* trigger on rising edge */
#define FLAG_ACTIVE_LOW	6	/* sysfs 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 ID_SHIFT	16	/* add new flags before this one */

#define GPIO_FLAGS_MASK		((1 << ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK	(BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))

#ifdef CONFIG_DEBUG_FS
	const char		*label;
#endif
};
主要就是有个 struct gpio_chip类型的指针

回到gpiod_request,其他代码先忽略,主要就两句,就是我加注释的地方

static int gpiod_request(struct gpio_desc *desc, const char *label)
{
	struct gpio_chip	*chip;
	int			status = -EPROBE_DEFER;
	unsigned long		flags;

	if (!desc) {
		pr_warn("%s: invalid GPIO\n", __func__);
		return -EINVAL;
	}

	spin_lock_irqsave(&gpio_lock, flags);

	chip = desc->chip;//取得desc中的struct gpio_chip.
	if (chip == NULL)
		goto done;

	if (!try_module_get(chip->owner))
		goto done;

	/* NOTE:  gpio_request() can be called in early boot,
	 * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
	 */

	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
		desc_set_label(desc, label ? : "?");
		status = 0;
	} else {
		status = -EBUSY;
		module_put(chip->owner);
		goto done;
	}

	if (chip->request) {
		/* chip->request may sleep */
		spin_unlock_irqrestore(&gpio_lock, flags);
		status = chip->request(chip, gpio_chip_hwgpio(desc));//调用desc[gpio]-〉chip-〉request
		spin_lock_irqsave(&gpio_lock, flags);

		if (status < 0) {
			desc_set_label(desc, NULL);
			module_put(chip->owner);
			clear_bit(FLAG_REQUESTED, &desc->flags);
			goto done;
		}
	}
	if (chip->get_direction) {
		/* chip->get_direction may sleep */
		spin_unlock_irqrestore(&gpio_lock, flags);
		gpiod_get_direction(desc);
		spin_lock_irqsave(&gpio_lock, flags);
	}
done:
	if (status)
		pr_debug("_gpio_request: gpio-%d (%s) status %d\n",
			 desc_to_gpio(desc), label ? : "?", status);
	spin_unlock_irqrestore(&gpio_lock, flags);
	return status;
}

chip-〉request有两个参数,一个是chip另一个是

/*
 * Return the GPIO number of the passed descriptor relative to its chip
 */
static int gpio_chip_hwgpio(const struct gpio_desc *desc)
{
	return desc - &desc->chip->desc[0];
}

看注释也很清楚,gpio号相对于它的chip的偏移。 看来这个struct gpio_chip非常重要,看看这个chip是在哪里赋值到gpio_desc[]这个数组的。
/**
 * gpiochip_add() - register a gpio_chip
 * @chip: the chip to register, with chip->base initialized
 * Context: potentially before irqs or kmalloc will work
 *
 * Returns a negative errno if the chip can't be registered, such as
 * because the chip->base is invalid or already associated with a
 * different chip.  Otherwise it returns zero as a success code.
 *
 * When gpiochip_add() is called very early during boot, so that GPIOs
 * can be freely used, the chip->dev device must be registered before
 * the gpio framework's arch_initcall().  Otherwise sysfs initialization
 * for GPIOs will fail rudely.
 *
 * If chip->base is negative, this requests dynamic assignment of
 * a range of valid GPIOs.
 */
int gpiochip_add(struct gpio_chip *chip)
{
..........略
	if (status == 0) {
		chip->desc = &gpio_desc[chip->base];

		for (id = 0; id < chip->ngpio; id++) {
			struct gpio_desc *desc = &chip->desc[id];
			desc->chip = chip;

			/* REVISIT:  most hardware initializes GPIOs as
			 * inputs (often with pullups enabled) so power
			 * usage is minimized.  Linux code should set the
			 * gpio direction first thing; but until it does,
			 * and in case chip->get_direction is not set,
			 * we may expose the wrong direction in sysfs.
			 */
			desc->flags = !chip->direction_input
				? (1 << FLAG_IS_OUT)
				: 0;
		}
	}

..............略

}

在这个函数里面全局数组gpio_desc被一一赋值了。

而这个gpiochip_add会在底层芯片厂商各自的gpio初始化函数里调用。 位置通常在各厂商各自的gpio-xxx.c

struct gpio_chip也会在那里定义,通常与硬件寄存器相关,不做分析。


gpio_request完了,还有gpio_to_irq,其实是一样的,还是最终会调用,stuct gpio_chip中的to_irq。


反过来说bsp的编写者,初始化之后,只要实现stuct gpio_chip 再调用gpiochip_add,gpio的API就可以供用户使用了。





 
 

你可能感兴趣的:(linux,嵌入式)