GPIO子系统
1.GPIO子系统作用
-
GPIO说明
芯片有很多引脚,每个引脚的功能很多,可用作GPIO、I2C、UART、SPI等功能,在Pincrt子系统篇,讲解了Pinctrl子系统,我们可以通过Pinctrl子系统对选择引脚的复用功能(如复用为GPIO或I2C等功能)以及配置引脚(上拉、下拉、驱动能力等)。
当一个引脚被复用为GPIO功能时,我们可以去设置它的方向(Input or Output),读取它的状态,GPIO名为"General Purpose Input/Output",通用目的的输入/输出,GPIO可以是芯片自带的,也可以使用扩展芯片通过I2C、SPI接口来扩展。
-
GPIO子系统作用
为了方便管理GPIO,linux内核抽象除了GPIO子系统,它既能支持芯片本身的GPIO,也能支持扩展的GPIO,提供统一的、简便的访问接口,实现GPIO基本的输入输出和中断操作。
在没有使用GPIO子系统时,我们使用一个引脚作为GPIO功能时,要通过寄存器来操作GPIO的引脚,对于不公的SOC,它的代码就不相同。
引入了GPIO子系统之后,我们就可以通过GPIO子系统来操作GPIO,操作方式如下:
- 在设备树中指定GPIO引脚
- 在驱动代码中:使用GPIO子系统提供的标准函数获取GPIO、设置GPIO方向、读取/设置GPIO值,而这段代码对于所有的SOC使用来说都是一样的。
2.GPIO子系统结构和相关数据结构
一般在驱动中使用GPIO,都是调用标准函数来操作GPIO,那标准函数是如何操作GPIO呢,下面是我整理的一个基本的框架图
上述框架图中牵扯到几个重要的结构体:
- struct gpio_device:用来描述一个gpio设备的状态和属性,如这个gpio设备有多少个pin,以及对每个pin的描述,最重要的struct gpio_chip结构体,它是gpio controller的抽象,用来控制引脚。例如在STM32MP157中的GPIOA就可以被抽象为一个struct gpio_device结构体,用来描述GPIOA的状态及属性,它下面有一个gpio_chip,里边有各种对gpio的操作,就是操作gpio0~gpio15。
- struct gpio_chip: 内核中对gpio controller的抽象,用来控制gpio device下都有一个gpio_chip,用来操作gpio device下的pin。
gpio controller中会对每一个pin进行编号,例如GPIOA0GPIO15编号015,GPIOB0GPIOB15编号1631等等,假如如我们GPIOA操作,在设备树中的节点就如下:
设备树:
beep-gpio = <&gpioa 0 GPIO_ACTIVE_HIGH>;
如果在驱动中我们要使用gpioa0这个pin,首先我们会使用of_get_named_gpio来解析设备节点,解析的结果就是获取gpio编号,后续对gpio的操作都是基于这个编号来操作。
驱动程序:
int beep_gpio;
beep_gpio=of_get_named_gpio(beep.node,"beep-gpio",0);
例如对于上面的gpioa0进行request操作流程就如下:
- 第一步:设备树中指定引脚gpioa0:beep-gpio = <&gpioa 0 GPIO_ACTIVE_HIGH>;
- 第二步:驱动程序中解析设备节点,获取gpioa0编号:beep_gpio=of_get_named_gpio(beep.node,“beep-gpio”,0);
- 第三步:调用gpiolib库中的标准gpio操作API函数gpio_request():gpio_request(beep_gpio,“BEEP-GPIO”);
- gpio_request()函数中根据gpioa0编号找到GPIOA对应的gpio device
- 调用GPIOA对应的gpio device下的gpio chip中的requst()函数来操作gpioa0
其他的gpio操作与上面的过程一致
将GPIO设备的抽象为struct gpio_device结构体:例如STM32MP157中GPIOA就是一个GPIO设备,最终我们可以使用struct gpio_device来描述GPIO的属性和状态
struct gpio_device {
int id;
struct device dev;
struct cdev chrdev;
struct device *mockdev;
struct module *owner;
/* chip: gpio controller的抽象,用来直接对引脚的控制*/
struct gpio_chip *chip;
/* descs:用来描述gpio的数组,每个gpio_controller下的所有gpio都会在这个数组中进行描述 */
struct gpio_desc *descs;
int base;/* GPIO编号基值 */
u16 ngpio;
const char *label;
void *data;
struct list_head list;
#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
};
struct gpio_chip :gpio controller的抽象,就是对gpio最底层的控制,它里边的操作函数就是直接的通过控制寄存器来操作GPIO
struct gpio_chip {
const char *label;
struct gpio_device *gpiodev;
struct device *parent;
struct module *owner;
int (*request)(struct gpio_chip *chip,
unsigned offset);
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);
int (*direction_output)(struct gpio_chip *chip,
unsigned offset, int value);
int (*get)(struct gpio_chip *chip,
unsigned offset);
int (*get_multiple)(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
void (*set_multiple)(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits);
int (*set_config)(struct gpio_chip *chip,
unsigned offset,
unsigned long config);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip);
int (*init_valid_mask)(struct gpio_chip *chip,
unsigned long *valid_mask,
unsigned int ngpios);
int base;
u16 ngpio;
const char *const *names;
bool can_sleep;
#if IS_ENABLED(CONFIG_GPIO_GENERIC)
unsigned long (*read_reg)(void __iomem *reg);
void (*write_reg)(void __iomem *reg, unsigned long data);
bool be_bits;
void __iomem *reg_dat;
void __iomem *reg_set;
void __iomem *reg_clr;
void __iomem *reg_dir_out;
void __iomem *reg_dir_in;
bool bgpio_dir_unreadable;
int bgpio_bits;
spinlock_t bgpio_lock;
unsigned long bgpio_data;
unsigned long bgpio_dir;
#endif /* CONFIG_GPIO_GENERIC */
#ifdef CONFIG_GPIOLIB_IRQCHIP
struct gpio_irq_chip irq;
#endif /* CONFIG_GPIOLIB_IRQCHIP */
unsigned long *valid_mask;
#if defined(CONFIG_OF_GPIO)
struct device_node *of_node;
unsigned int of_gpio_n_cells;
int (*of_xlate)(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags);
#endif /* CONFIG_OF_GPIO */
};
综合上述代码我们可以看出对GPIO操作最底层的操作就是通过gpio_chip结构体来实现,其他从gpiolib库到调用gpio_chip结构体中的函数这个框架内核的gpio子系统驱动已经帮我们写好了,假如我们自己要写一个gpio controller驱动,我们只需要构建gpio_chip,所以写一个gpio controller驱动就有以下三个步骤:
- 第一步:分配gpio_chip结构体
- 第二步:设置gpio_chip结构体
- 第三步:注册gpio_chip结构体,注册采用gpiochip_add_data()函数,在include/linux/gpio/driver.h文件中定义,注册时会自动创建struct gpio_device结构体。
3.STM32MP157中GPIO Controller的实现过程
-
设备树
gpio controller在设备树中的描述:它分别在两个文件中进行了描述,arch/arm/boot/dts/stm32mp151.dtsi和
arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi文件,现在我把它合并为一个,如下:
pinctrl: pin-controller@50002000 { #address-cells = <1>; #size-cells = <1>; compatible = "st,stm32mp157-pinctrl"; ranges = <0 0x50002000 0xa400>; interrupt-parent = <&exti>; st,syscfg = <&exti 0x60 0xff>; hwlocks = <&hsem 0 1>; pins-are-numbered; gpioa: gpio@50002000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x0 0x400>; clocks = <&rcc GPIOA>; st,bank-name = "GPIOA"; status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 0 16>; }; gpiob: gpio@50003000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x1000 0x400>; clocks = <&rcc GPIOB>; st,bank-name = "GPIOB"; status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 16 16>; }; ......... };
里边例举了两个节点gpioa和gpiob,剩下的和它们结构一样,里边都有一个gpio-controller属性,表明这个设备节点是一个gpio controller节点,而且里边没有compatible属性,它的父节点是pinctrl: pin-controller,这个是pin controller节点,所以gpio controller驱动是在pinctrl驱动中实现的。它实在pinctrl驱动中进行对gpio_chip结构体的分配、设置和注册的。
我们再来看它的驱动代码:
int stm32_pctl_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node;/* 对应的设备树节点 */ struct device_node *child; /* 子节点 */ const struct of_device_id *match; /* 设备驱动匹配项 */ struct device *dev = &pdev->dev;/* 对应的设备 */ struct stm32_pinctrl *pctl; /* STM32 pinctrl */ struct pinctrl_pin_desc *pins; /* pin脚描述 */ int i, ret, hwlock_id, banks = 0; ......... /* pin controller驱动代码部分 */ .......... /* gpio conroller驱动代码部分 */ for_each_available_child_of_node(np, child) if (of_property_read_bool(child, "gpio-controller")) /* 对于pincrtl下的每个子节点查找是否存在 gpio-controller属性,统计gpio controller的个数*/ banks++; if (!banks) { dev_err(dev, "at least one GPIO bank is required\n"); return -EINVAL; } /*struct stm32_pinctrl下的banks 为struct stm32_gpio_bank类型,在STM32MP157中将每个gpio设备抽象为struct stm32_gpio_bank,在struct stm32_gpio_bank下定义了 gpio_chip结构体,所以分配struct stm32_gpio_bank内存相当于也给gpio_chip分配了内存 */ pctl->banks = devm_kcalloc(dev, banks, sizeof(*pctl->banks), GFP_KERNEL); if (!pctl->banks) return -ENOMEM; i = 0; for_each_available_child_of_node(np, child) { /* GPIO设备的时钟配置 */ struct stm32_gpio_bank *bank = &pctl->banks[i]; if (of_property_read_bool(child, "gpio-controller")) { bank->rstc = of_reset_control_get_exclusive(child, NULL); if (PTR_ERR(bank->rstc) == -EPROBE_DEFER) return -EPROBE_DEFER; bank->clk = of_clk_get_by_name(child, NULL); if (IS_ERR(bank->clk)) { if (PTR_ERR(bank->clk) != -EPROBE_DEFER) dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(bank->clk)); return PTR_ERR(bank->clk); } i++; } } for_each_available_child_of_node(np, child) { if (of_property_read_bool(child, "gpio-controller")) { /* 对每个gpio controller节点进行注册,其中gpio_chip结构体的设置和注册就在这个函数中进行 */ ret = stm32_gpiolib_register_bank(pctl, child); if (ret) { of_node_put(child); return ret; } pctl->nbanks++; } } dev_info(dev, "Pinctrl STM32 initialized\n"); return 0; }
stm32_gpiolib_register_bank()函数解析
static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct device_node *np) { struct stm32_gpio_bank *bank = &pctl->banks[pctl->nbanks]; int bank_ioport_nr; struct pinctrl_gpio_range *range = &bank->range; struct of_phandle_args args; struct device *dev = pctl->dev; struct resource res; int npins = STM32_GPIO_PINS_PER_BANK; int bank_nr, err; if (!IS_ERR(bank->rstc)) reset_control_deassert(bank->rstc); if (of_address_to_resource(np, 0, &res)) return -ENODEV; bank->base = devm_ioremap_resource(dev, &res); if (IS_ERR(bank->base)) return PTR_ERR(bank->base); err = clk_prepare(bank->clk); if (err) { dev_err(dev, "failed to prepare clk (%d)\n", err); return err; } /* gpio_chip赋值,里边时gpio操作函数 static const struct gpio_chip stm32_gpio_template = { .request = stm32_gpio_request, .free = stm32_gpio_free, .get = stm32_gpio_get, .set = stm32_gpio_set, .direction_input = stm32_gpio_direction_input, .direction_output = stm32_gpio_direction_output, .to_irq = stm32_gpio_to_irq, .get_direction = stm32_gpio_get_direction, .set_config = gpiochip_generic_config, }; */ bank->gpio_chip = stm32_gpio_template; of_property_read_string(np, "st,bank-name", &bank->gpio_chip.label); /* 解析设备树节点中的gpio-ranges属性 例如:gpio-ranges = <&pinctrl 1 2 3>; 解析结果:args.args[0] = 1 args.args[1] = 2 args.args[2] = 3 我们可以从设备树中看出args[1]的这个值就是该gpio controller中pin 编号的基值 */ if (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args)) { /* GPIOA: args.args[1]=0 bank_nr=0 bank->gpio_chip.base=0 GPIOB: args.args[1]=16 bank_nr=1 bank->gpio_chip.base=16 GPIOC: args.args[1]=32 bank_nr=2 bank->gpio_chip.base=32 */ bank_nr = args.args[1] / STM32_GPIO_PINS_PER_BANK;/* 给bankb编号 */ bank->gpio_chip.base = args.args[1];/* pins编号基值 */ } else { bank_nr = pctl->nbanks; bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK; range->name = bank->gpio_chip.label; range->id = bank_nr; range->pin_base = range->id * STM32_GPIO_PINS_PER_BANK; range->base = range->id * STM32_GPIO_PINS_PER_BANK; range->npins = npins; range->gc = &bank->gpio_chip; pinctrl_add_gpio_range(pctl->pctl_dev, &pctl->banks[bank_nr].range); } if (of_property_read_u32(np, "st,bank-ioport", &bank_ioport_nr)) bank_ioport_nr = bank_nr; bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK; bank->gpio_chip.ngpio = npins; bank->gpio_chip.of_node = np; bank->gpio_chip.parent = dev; bank->bank_nr = bank_nr; bank->bank_ioport_nr = bank_ioport_nr; spin_lock_init(&bank->lock); /* create irq hierarchical domain */ bank->fwnode = of_node_to_fwnode(np); bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, STM32_GPIO_IRQ_LINE, bank->fwnode, &stm32_gpio_domain_ops, bank); if (!bank->domain) return -ENODEV; /* 注册struct gpio_chip结构体 */ err = gpiochip_add_data(&bank->gpio_chip, bank); if (err) { dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_nr); return err; } dev_info(dev, "%s bank added\n", bank->gpio_chip.label); return 0; }
最后调用gpiochip_add_data()注册gpio_chip结构体,接下来我们分析gpiochip_add_data()函数,在include/linux/gpio/driver.h文件中被宏定义:
#define gpiochip_add_data(chip, data) gpiochip_add_data_with_key(chip, data, NULL, NULL)
所以最终使用的函数为gpiochip_add_data_with_key();在drivers/gpio/gpiolib.c文件中定义
int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, struct lock_class_key *lock_key, struct lock_class_key *request_key) { unsigned long flags; int ret = 0; unsigned i; int base = chip->base; struct gpio_device *gdev; /* 分配并设置gpio_device结构体*/ gdev = kzalloc(sizeof(*gdev), GFP_KERNEL); if (!gdev) return -ENOMEM; gdev->dev.bus = &gpio_bus_type; /* gpio device 中的chip指向在上面驱动函数中构造的gpio chip */ gdev->chip = chip; chip->gpiodev = gdev; if (chip->parent) { gdev->dev.parent = chip->parent; gdev->dev.of_node = chip->parent->of_node; } #ifdef CONFIG_OF_GPIO /* If the gpiochip has an assigned OF node this takes precedence */ if (chip->of_node) gdev->dev.of_node = chip->of_node; else chip->of_node = gdev->dev.of_node; #endif gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL); if (gdev->id < 0) { ret = gdev->id; goto err_free_gdev; } dev_set_name(&gdev->dev, "gpiochip%d", gdev->id); device_initialize(&gdev->dev); dev_set_drvdata(&gdev->dev, gdev); if (chip->parent && chip->parent->driver) gdev->owner = chip->parent->driver->owner; else if (chip->owner) /* TODO: remove chip->owner */ gdev->owner = chip->owner; else gdev->owner = THIS_MODULE; /* 分配struct gpio_desc结构体数组,用来描述gpio device下的每个gpio struct gpio_desc { struct gpio_device *gdev; 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_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ #define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ /* Connection label const char *label; Name of the GPIO const char *name; }; */ gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL); if (!gdev->descs) { ret = -ENOMEM; goto err_free_ida; } if (chip->ngpio == 0) { chip_err(chip, "tried to insert a GPIO chip with zero lines\n"); ret = -EINVAL; goto err_free_descs; } if (chip->ngpio > FASTPATH_NGPIO) chip_warn(chip, "line cnt %u is greater than fast path cnt %u\n", chip->ngpio, FASTPATH_NGPIO); gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { ret = -ENOMEM; goto err_free_descs; } gdev->ngpio = chip->ngpio; gdev->data = data; spin_lock_irqsave(&gpio_lock, flags); /* * TODO: this allocates a Linux GPIO number base in the global * GPIO numberspace for this chip. In the long run we want to * get *rid* of this numberspace and use only descriptors, but * it may be a pipe dream. It will not happen before we get rid * of the sysfs interface anyways. */ if (base < 0) { base = gpiochip_find_base(chip->ngpio); if (base < 0) { ret = base; spin_unlock_irqrestore(&gpio_lock, flags); goto err_free_label; } /* * TODO: it should not be necessary to reflect the assigned * base outside of the GPIO subsystem. Go over drivers and * see if anyone makes use of this, else drop this and assign * a poison instead. */ chip->base = base; } gdev->base = base; /* 将gpio device添加到链表中 */ ret = gpiodev_add_to_list(gdev); if (ret) { spin_unlock_irqrestore(&gpio_lock, flags); goto err_free_label; } spin_unlock_irqrestore(&gpio_lock, flags); for (i = 0; i < chip->ngpio; i++) gdev->descs[i].gdev = gdev; #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif ret = gpiochip_set_desc_names(chip); if (ret) goto err_remove_from_list; ret = gpiochip_alloc_valid_mask(chip); if (ret) goto err_remove_from_list; ret = of_gpiochip_add(chip); if (ret) goto err_free_gpiochip_mask; ret = gpiochip_init_valid_mask(chip); if (ret) goto err_remove_of_chip; /* 对每个gpio在gpio device下的descs结构体数组中进行描述 */ for (i = 0; i < chip->ngpio; i++) { struct gpio_desc *desc = &gdev->descs[i]; if (chip->get_direction && gpiochip_line_is_valid(chip, i)) { if (!chip->get_direction(chip, i)) set_bit(FLAG_IS_OUT, &desc->flags); else clear_bit(FLAG_IS_OUT, &desc->flags); } else { if (!chip->direction_input) set_bit(FLAG_IS_OUT, &desc->flags); else clear_bit(FLAG_IS_OUT, &desc->flags); } } ............................... }
STM32MP157的gpio controller驱动程序我们就分析到这里,看上去很复杂,其实也就是实现前面所分析的三步:第一步:分配gpio_chip结构体;第二步:设置gpio_chip结构体;第三步:注册gpio_chip结构体