LV520-gpio驱动分析
gpio1 节点的 compatible 属性描述了兼容性,在 Linux 内核中搜索“fsl, imx6ul-gpio”和“fsl, imx35-gpio”这两个字符串,查找 GPIO 驱动文件。gpio-mxc.c - drivers/gpio/gpio-mxc.c 就是 I.MX6ULL 的 GPIO 驱动文件。这里就不再详细去分析了,也挺复杂的,感觉会用就行了。
一、核心数据结构
这里大概了解下重要的 3 个核心数据结构。记住 GPIO Controller 的要素,这有助于理解它的驱动程序:
- 一个 GPIO Controller 里有多少个引脚?有哪些引脚?
- 需要提供函数,设置引脚方向、读取/设置数值
- 需要提供函数,把引脚转换为中断
以 Linux 面向对象编程的思想,一个 GPIO Controller 必定会使用一个结构体来表示,这个结构体必定含有这些信息:
- GPIO 引脚信息
- 控制引脚的函数
- 中断相关的函数
1. gpio_device
每个 GPIO Controller 用一个 gpio_device 来表示:
struct gpio_device {
int id; // 它是系统中第几个 GPIO Controller
struct device dev;
struct cdev chrdev;
struct device *mockdev;
struct module *owner;
struct gpio_chip *chip; // 含有各类操作函数
struct gpio_desc *descs; // 用来描述引脚,每个引脚对应一个 gpio_desc
int base; // 这些 GPIO 的号码基值
u16 ngpio; // 这个 GPIO Controller 支持多少个 gpio
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
};2. gpio_chip
我们并不需要自己创建 gpio_device,编写驱动时要创建的是 gpio_chip,里面提供了:
- 控制引脚的函数
- 中断相关的函数
- 引脚信息:支持多少个引脚?各个引脚的名字?
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);
//......
int base; // GPIO Controller 中引脚号码的基值,个数
u16 ngpio;
const char *const *names;// 每个引脚的名字
bool can_sleep;
//......
};这一结构体用于描述 GPIO 芯片的属性和操作函数, 可以通过函数指针调用相应的函数来请求、 释放、 设置、 获取 GPIO 的状态和数值等操作, 从而实现对 GPI O 的控制和管理, 需要注意的是这个结构体中的一系列函数都不需要我们来填充, 这些工作都是由芯片原厂工程师来完成的。
3. gpio_desc
我们去使用 GPIO 子系统时,首先是获得某个引脚对应的 gpio_desc。gpio_device 表示一个 GPIO Controller,也就是 GPIO 控制器,每个控制器里面支持多个 GPIO。在 gpio_device 中有一个 gpio_desc 数组,每一引脚有一项 gpio_desc。
struct gpio_desc {
struct gpio_device *gdev; // 属于哪个 GPIO Controller
unsigned long flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
//......
/* Connection label */
const char *label; // 一般等于 gpio_chip 的 label
/* Name of the GPIO */
const char *name; // 引脚名
};二、gpio 子系统驱动
这个驱动就不详细去看了,imx6ull 平台的 gpio 子系统驱动相关的代码在这里:gpio-mxc.c - drivers/gpio/gpio-mxc.c - Linux source code v4.19.71,这个也是平台设备驱动,驱动的匹配表 mxc_gpio_dt_ids 如下:
static const struct of_device_id mxc_gpio_dt_ids[] = {
{ .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], },
{ .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], },
{ .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], },
{ .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
{ .compatible = "fsl,imx7d-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
{ /* sentinel */ }
};