在Linux内核的GPIO子系统中,gpio_chip
并不对应单个GPIO引脚,而是代表一个完整的GPIO控制器(如SoC内置的GPIO模块或I2C/SPI扩展的GPIO芯片)。以下是关键点解析:
1. gpio_chip
的核心作用
- 管理一组GPIO引脚:一个
gpio_chip
实例对应一个物理GPIO控制器,负责管理该控制器下的所有引脚(如32个或64个引脚)。 - 提供硬件操作接口:
direction_input()
: 设置引脚为输入模式。get()
: 读取引脚电平。direction_output()
: 设置引脚为输出模式。set()
: 写入引脚电平。
- 元数据:
base
: 控制器管理的起始GPIO编号(如base=100
表示该控制器的GPIO从全局编号100开始)。ngpio
: 控制器管理的引脚总数(如ngpio=32
表示管理GPIO 100-131)。label
: 控制器名称(如"imx6ul-gpio1"
)。
2. 单个引脚的表示:gpio_desc
gpio_desc
对应单个引脚:每个GPIO引脚在内核中由gpio_desc
结构体描述,包含:- 关联的
gpio_chip
(通过chip
字段)。 - 引脚在控制器内的偏移量(
offset = gpio - chip->base
)。 - 配置信息(如方向、标签、消费者设备)。
- 关联的
- 全局编号与描述符的转换:
- 通过
gpio_to_desc(gpio)
将全局GPIO编号(如105)转换为对应的gpio_desc
。 - 通过
desc_to_gpio(desc)
反向转换。
- 通过
3. 关系图示
gpio_chip (控制器)
├── base: 100 (全局GPIO起始编号)
├── ngpio: 32 (管理32个引脚)
└── 操作函数:
- direction_input()
- get()
- set()
gpio_desc (引脚描述符)
├── chip: &gpio_chip (指向关联的控制器)
├── offset: 5 (在控制器内的偏移量,对应GPIO 100+5=105)
└── 配置: 输出模式, 标签"led_gpio"
4. 驱动中的典型操作
(1) 注册GPIO控制器
static struct gpio_chip my_gpio_chip = {
.label = "my-gpio",
.direction_input = my_dir_input,
.get = my_get_value,
.direction_output = my_dir_output,
.set = my_set_value,
.base = 0, // 实际编号由内核分配
.ngpio = 32, // 管理32个引脚
};
// 注册控制器到内核
gpiochip_add(&my_gpio_chip);
(2) 操作单个引脚(通过gpio_desc
)
// 获取GPIO描述符(假设设备树中配置了GPIO 105)
struct gpio_desc *led_gpio = gpiod_get(dev, "led", GPIOD_OUT_HIGH);
if (IS_ERR(led_gpio)) {
// 错误处理
}
// 写入高电平(通过描述符操作)
gpiod_set_value(led_gpio, 1);
5. 关键结论
gpio_chip
是控制器级别的抽象,负责管理一组GPIO引脚并提供底层硬件操作接口。gpio_desc
是引脚级别的抽象,描述单个引脚的配置和元数据。- 驱动开发中:
- 实现
gpio_chip
以支持硬件控制器。 - 通过
gpio_desc
安全地操作具体引脚(避免直接使用全局GPIO编号)。
- 实现
这种设计实现了控制器与引脚的解耦,使GPIO子系统能够统一管理不同硬件平台的GPIO资源。