最近用到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_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);
}
都在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];
}
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];
}
/**
* 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就可以供用户使用了。