在Linux中,会在gpiolib.c中定义一个 ARCH_NR_GPIOS 大小的数组static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];。每个元素对应于当前CPU上各个GPIO接口的信息,记录各个GPIO的描述符,即对应struct gpio_desc结构体。struct gpio_desc内的成员gpio_chip又指向了一系列关于GPIO的操作。具体的操作在 driver/gpio/gpio_**.c中实现。
gpio_desc结构体中,flags为一标志位,用来指示当前GPIO是否已经占用,当用gpio_request申请GPIO资源时,flags位就会置位,当调用gpio_free释放GPIO资源时,flags就会清零。
当我们调用gpio_request(),实际上会将参数gpio在数组中查找其对应的gpio_desc,在根据gpio_chip就可以找到底层关于request()的实现。
所有的GPIO控制器驱动应包括下面的头文件,包含 struct gpio_chip 的定义。 include <linux/gpio/driver.h>
struct gpio_chip:标记GPIO所属的控制器,里面包含诸多回调函数,用于控制GPIO的行为,各个板卡都有实现自己的gpio_chip控制模块;
struct gpio_desc:用于标记一个GPIO;
在driver/gpio/gpio_**.c文件中会注册特定平台**的GPIO驱动 定义了GPIO板级控制的内容,包括设置 set gpio,get gpio,dir_in,dir_out,gpio_to_irq等行为; 获取GPIO板级的资源,包括 gpio_reg_base,并赋值给 struct gpio_chip; 将struct gpio_chip添加到GPIOLIB中;
driver/gpio/gpio_**.c会定义平台驱动并初始化
板级文件或设备树会添加平台设备
当设备与驱动匹配就会执行**_gpio_probe()的内容。
probe() 中初始化struct gpio_chip结构体的成员。并调用 gpiochip_add()将gpio_chip添加到 GPIOLIB 中。
GPIOLIB 提供GPIO调用的接口函数。比如常见的 gpio_request()/gpio_free()/gpio_get_value()/gpio_is_valid() 等。 相关结构体gpio_chip代表一个芯片的一个gpio bank
struct gpio_chip { const char *label; struct device *dev; struct module *owner; int (*request)(struct gpio_chip *chip,unsigned offset); void (*free)(struct gpio_chip *chip,unsigned offset); int (*direction_input)(struct gpio_chip *chip,unsigned offset); int (*get)(struct gpio_chip *chip,unsigned offset); int (*direction_output)(struct gpio_chip *chip,unsigned offset, int value); int (*direction_output_array)(struct gpio_chip*chip, unsigned value, unsigned mask); int (*set_debounce)(struct gpio_chip *chip,unsigned offset, unsigned debounce); void (*set)(struct gpio_chip *chip,unsigned offset, int value); int (*to_irq)(struct gpio_chip *chip,unsigned offset); void (*dbg_show)(struct seq_file *s,struct gpio_chip *chip); int base; u16 ngpio; const char *const *names; unsigned can_sleep:1; unsigned exported:1; #if defined(CONFIG_OF_GPIO) struct device_node *of_node; int of_gpio_n_cells; int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,const void *gpio_spec, u32 *flags); #endif }; gpio_desc 代表一个gpio口
struct gpio_desc { struct gpio_chip *chip; unsigned long flags; #ifdef CONFIG_DEBUG_FS const char *label; #endif }; 2.1 gpio_desc flags标志 #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 #define FLAG_RESERVED 2 #define FLAG_EXPORT 3 #define FLAG_SYSFS 4 #define FLAG_TRIG_FALL 5 #define FLAG_TRIG_RISE 6 #define FLAG_ACTIVE_LOW 7 2.2 全局gpio_desc数组 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; gpio类
static struct class gpio_class = { .name = "gpio", .owner = THIS_MODULE, .class_attrs = gpio_class_attrs, }; api接口int gpiochip_add(struct gpio_chip *chip) int gpiochip_remove(struct gpio_chip *chip) struct gpio_chip *gpiochip_find(void *data,int (*match)(struct gpio_chip *chip, void *data)) int gpio_request(unsigned gpio, const char *label) void gpio_free(unsigned gpio) int gpio_set_debounce(unsigned gpio, unsigned debounce) int gpio_direction_input(unsigned gpio) int gpio_direction_output(unsigned gpio, int value) int gpio_cansleep(unsigned gpio) int gpio_get_value_cansleep(unsigned gpio) void gpio_set_value_cansleep(unsigned gpio, int value) int gpio_get_value(unsigned gpio) int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) int gpio_request_array(struct gpio *array, size_t num) void gpio_free_array(struct gpio *array, size_t num) int gpio_to_irq(unsigned gpio) int gpio_export(unsigned gpio, bool direction_may_change) void gpio_unexport(unsigned gpio) api及调用到的相关函数解析1. 设置gpio_chip管理的全局gpio_desc数组项 int gpiochip_add(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; int base = chip->base; if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) && base >= 0) { status = -EINVAL; goto fail; } spin_lock_irqsave(&gpio_lock, flags); if (base < 0) { base = gpiochip_find_base(chip->ngpio); if (base < 0) { status = base; goto unlock; } chip->base = base; } status = gpiochip_add_to_list(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; desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } } spin_unlock_irqrestore(&gpio_lock, flags); if (status) goto fail; #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&chip->pin_ranges); #endif of_gpiochip_add(chip); acpi_gpiochip_add(chip); status = gpiochip_export(chip); if (status) { acpi_gpiochip_remove(chip); of_gpiochip_remove(chip); goto fail; } pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return 0; unlock: spin_unlock_irqrestore(&gpio_lock, flags); fail: pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status; } EXPORT_SYMBOL_GPL(gpiochip_add); 2. 清空gpio_chip管理的全局gpio_desc数组项 int gpiochip_remove(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; spin_lock_irqsave(&gpio_lock, flags); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); acpi_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { status = -EBUSY; break; } } if (status == 0) { for (id = 0; id < chip->ngpio; id++) chip->desc[id].chip = NULL; list_del(&chip->list); } spin_unlock_irqrestore(&gpio_lock, flags); if (status == 0) gpiochip_unexport(chip); return status; } EXPORT_SYMBOL_GPL(gpiochip_remove);
3. 查找获取gpio_chip struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, void *data)) { struct gpio_chip *chip; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(chip, &gpio_chips, list) if (match(chip, data)) break; if (&chip->list == &gpio_chips) chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); return chip; } EXPORT_SYMBOL_GPL(gpiochip_find);
4. 请求gpio资源 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; if (chip == NULL) goto done; if (!try_module_get(chip->owner)) goto done; 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) { spin_unlock_irqrestore(&gpio_lock, flags); status = chip->request(chip, gpio_chip_hwgpio(desc)); 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) { spin_unlock_irqrestore(&gpio_lock, flags); gpiod_get_direction(desc); spin_lock_irqsave(&gpio_lock, flags); } done: if (status) gpiod_dbg(desc, "%s: status %d\n", __func__, status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } int gpio_request(unsigned gpio, const char *label) { return gpiod_request(gpio_to_desc(gpio), label); } EXPORT_SYMBOL_GPL(gpio_request);
5. 释放gpio资源 static void gpiod_free(struct gpio_desc *desc) { unsigned long flags; struct gpio_chip *chip; might_sleep(); if (!desc) { WARN_ON(extra_checks); return; } gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); chip = desc->chip; if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (chip->free) { spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); chip->free(chip, gpio_chip_hwgpio(desc)); spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); module_put(desc->chip->owner); clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); } else WARN_ON(extra_checks); spin_unlock_irqrestore(&gpio_lock, flags); } void gpio_free(unsigned gpio) { gpiod_free(gpio_to_desc(gpio)); } EXPORT_SYMBOL_GPL(gpio_free); 6. 设置去抖动时间 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } chip = desc->chip; if (!chip->set || !chip->set_debounce) { gpiod_dbg(desc, "%s: missing set() or set_debounce() operations\n", __func__); return -ENOTSUPP; } spin_lock_irqsave(&gpio_lock, flags); status = gpio_ensure_requested(desc); if (status < 0) goto fail; spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); offset = gpio_chip_hwgpio(desc); return chip->set_debounce(chip, offset, debounce); fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_set_debounce); 7. 设置gpio为输入io int gpiod_direction_input(struct gpio_desc *desc) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } chip = desc->chip; if (!chip->get || !chip->direction_input) { gpiod_warn(desc, "%s: missing get() or direction_input() operations\n", __func__); return -EIO; } spin_lock_irqsave(&gpio_lock, flags); status = gpio_ensure_requested(desc); if (status < 0) goto fail; spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); offset = gpio_chip_hwgpio(desc); if (status) { status = chip->request(chip, offset); if (status < 0) { gpiod_dbg(desc, "%s: chip request fail, %d\n", __func__, status); goto lose; } } status = chip->direction_input(chip, offset); if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); trace_gpio_direction(desc_to_gpio(desc), 1, status); lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_direction_input);
8. 设备gpio为输出io int gpiod_direction_output(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, "%s: tried to set a GPIO tied to an IRQ as output\n", __func__); return -EIO; } if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) return gpiod_direction_input(desc); if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) return gpiod_direction_input(desc); chip = desc->chip; if (!chip->set || !chip->direction_output) { gpiod_warn(desc, "%s: missing set() or direction_output() operations\n", __func__); return -EIO; } spin_lock_irqsave(&gpio_lock, flags); status = gpio_ensure_requested(desc); if (status < 0) goto fail; spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); offset = gpio_chip_hwgpio(desc); if (status) { status = chip->request(chip, offset); if (status < 0) { gpiod_dbg(desc, "%s: chip request fail, %d\n", __func__, status); goto lose; } } status = chip->direction_output(chip, offset, value); if (status == 0) set_bit(FLAG_IS_OUT, &desc->flags); trace_gpio_value(desc_to_gpio(desc), 0, value); trace_gpio_direction(desc_to_gpio(desc), 0, status); lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_direction_output);
用户态使用gpio监听中断首先需要将该gpio配置为中断
echo "rising" > /sys/class/gpio/gpio12/edge nt gpio_id; struct pollfd fds[1]; gpio_fd = open("/sys/class/gpio/gpio12/value",O_RDONLY); if( gpio_fd == -1 ) err_print("gpio open"); fds[0].fd = gpio_fd; fds[0].events = POLLPRI; ret = read(gpio_fd,buff,10); if( ret == -1 ) err_print("read"); while(1){ ret = poll(fds,1,-1); if( ret == -1 ) err_print("poll"); if( fds[0].revents & POLLPRI){ ret = lseek(gpio_fd,0,SEEK_SET); if( ret == -1 ) err_print("lseek"); ret = read(gpio_fd,buff,10); if( ret == -1 ) err_print("read"); ............... } } 记住使用poll()函数,设置事件监听类型为POLLPRI和POLLERR在poll()返回后,使用lseek()移动到文件开头读取新的值或者关闭它再重新打开读取新值。必须这样做否则poll函数会总是返回。
|