1. 概述
如果
pinctrl
子系统将一个 PIN 复用为 GPIO 的话,那么接下来要用到 gpio 子系统了。gpio 子系统顾名思义,就是用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,设置读取 GPIO 的值等。gpio 子系统的主要目的就是方便驱动开发者使用 gpio,驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO,Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程,极大的方便了驱动开发者使用 GPIO
Linux的GPIO子系统驱动框架由三个主要部分组成:① GPIO控制器驱动程序、②gpio lib驱动程序 ③GPIO字符设备驱动程序:
2. gpio 子系统相关结构体
2.1 struct gpio_chip
/*** struct gpio_chip - abstract a GPIO controller* @label: for diagnostics* @dev: optional device providing the GPIOs* @owner: helps prevent removal of modules exporting active GPIOs* @list: links gpio_chips together for traversal* @request: optional hook for chip-specific activation, such as* enabling module power and clock; may sleep* @free: optional hook for chip-specific deactivation, such as* disabling module power and clock; may sleep* @get_direction: returns direction for signal "offset", 0=out, 1=in,* (same as GPIOF_DIR_XXX), or negative error* @direction_input: configures signal "offset" as input, or returns error* @direction_output: configures signal "offset" as output, or returns error* @get: returns value for signal "offset"; for output signals this* returns either the value actually sensed, or zero* @set: assigns output value for signal "offset"* @set_multiple: assigns output values for multiple signals defined by "mask"* @set_debounce: optional hook for setting debounce time for specified gpio in* interrupt triggered gpio chips* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;* implementation may not sleep* @dbg_show: optional routine to show contents in debugfs; default code* will be used when this is omitted, but custom code can show extra* state (such as pullup/pulldown configuration).* @base: identifies the first GPIO number handled by this chip; or, if* negative during registration, requests dynamic ID allocation.* @ngpio: the number of GPIOs handled by this controller; the last GPIO* handled is (base + ngpio - 1).* @desc: array of ngpio descriptors. Private.* @names: if set, must be an array of strings to use as alternative* names for the GPIOs in this chip. Any entry in the array* may be NULL if there is no alias for the GPIO, however the* array must be @ngpio entries long. A name can include a single printk* format specifier for an unsigned int. It is substituted by the actual* number of the gpio.* @can_sleep: flag must be set iff get()/set() methods sleep, as they* must while accessing GPIO expander chips over I2C or SPI. This* implies that if the chip supports IRQs, these IRQs need to be threaded* as the chip access may sleep when e.g. reading out the IRQ status* registers.* @exported: flags if the gpiochip is exported for use from sysfs. Private.* @irq_not_threaded: flag must be set if @can_sleep is set but the* IRQs don't need to be threaded** A gpio_chip can help platforms abstract various sources of GPIOs so* they can all be accessed through a common programing interface.* Example sources would be SOC controllers, FPGAs, multifunction* chips, dedicated GPIO expanders, and so on.** Each chip controls a number of signals, identified in method calls* by "offset" values in the range 0..(@ngpio - 1). When those signals* are referenced through calls like gpio_get_value(gpio), the offset* is calculated by subtracting @base from the gpio number.*/
struct gpio_chip {const char *label;struct device *dev;struct module *owner;struct list_head list;//请求一个 GPIO引脚int (*request)(struct gpio_chip *chip,unsigned offset);//释放一个GPIO引脚void (*free)(struct gpio_chip *chip,unsigned offset);//获取方向int (*get_direction)(struct gpio_chip *chip,unsigned offset);//输入模式int (*direction_input)(struct gpio_chip *chip,unsigned offset);//输出模式,并且set gpio valint (*direction_output)(struct gpio_chip *chip,unsigned offset, int value);//读取 GPIO 引脚的值int (*get)(struct gpio_chip *chip,unsigned offset);//设置gpio 引脚值void (*set)(struct gpio_chip *chip,unsigned offset, int value);//设置多个gpio 引脚值void (*set_multiple)(struct gpio_chip *chip,unsigned long *mask,unsigned long *bits);//设置 GPIO 引脚的去抖动时间int (*set_debounce)(struct gpio_chip *chip,unsigned offset,unsigned debounce);int (*to_irq)(struct gpio_chip *chip,unsigned offset);void (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);int base; //chip的基地址u16 ngpio; //GPIO 引脚数量struct gpio_desc *desc; //gpio描述结构体数组,里面保存了此控制器可以控制的引脚描述const char *const *names;bool can_sleep;bool irq_not_threaded;bool exported;#ifdef CONFIG_GPIOLIB_IRQCHIP/** With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib* to handle IRQs for most practical cases.*/struct irq_chip *irqchip;struct irq_domain *irqdomain;unsigned int irq_base;irq_flow_handler_t irq_handler;unsigned int irq_default_type;
#endif#if defined(CONFIG_OF_GPIO)/** If CONFIG_OF is enabled, then all GPIO controllers described in the* device tree automatically may have an OF translation*/struct device_node *of_node;int of_gpio_n_cells;int (*of_xlate)(struct gpio_chip *gc,const struct of_phandle_args *gpiospec, u32 *flags);
#endif
#ifdef CONFIG_PINCTRL/** If CONFIG_PINCTRL is enabled, then gpio controllers can optionally* describe the actual pin range which they serve in an SoC. This* information would be used by pinctrl subsystem to configure* corresponding pins for gpio usage.*/struct list_head pin_ranges;
#endif
};
2.2 struct gpio_desc
struct gpio_desc {struct gpio_chip *chip; //属于哪个gpio_chipunsigned 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 /* 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_SYSFS_DIR 10 /* show sysfs direction attribute */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */#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))const char *label;
};
3. IMX6ULL gpio-controller构造过程
4. gpiochip_add