GPIO子系统gpiolib
前言
在上一篇文章中说到在应用下如何操作gpio,以及简单分析了下gpioctl的驱动以及api的一些好处,本编文章就来介绍下gpiolib相关的一些api以及gpio的不同平台的注册相关内容。解析gpiolib是如何管理gpio的。
gpiolib相关api
这些api主要给其他驱动提供使用
申请
int gpio_request(unsigned gpio, const char *label) //申请一个gpio是否可用
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)//带属性的申请
int gpio_request_array(const struct gpio *array, size_t num) //申请一组
释放
void gpio_free(unsigned gpio)
void gpio_free_array(const struct gpio *array, size_t num)
控制
kernel\include\asm-generic\gpio.h
static inline int gpio_direction_input(unsigned gpio)
static inline int gpio_direction_output(unsigned gpio, int value)
下面两个一般用在gpio扩展芯片上,这类芯片的接口一般为i2c或者spi他们的设置操作可能引起休眠所以用不同的接口区分且这类接口不能用于中断中。
static inline int gpio_get_value_cansleep(unsigned gpio)
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
int __gpio_get_value(unsigned gpio)
void __gpio_set_value(unsigned gpio, int value)
int __gpio_to_irq(unsigned gpio) //中断相关
gpiolib重要内部接口
重要结构
struct gpio_device {
int id;
struct device dev;
struct cdev chrdev;
struct device *mockdev;
struct module *owner;
struct gpio_chip *chip; //重要
struct gpio_desc *descs;//重要
int base;//表示这一组base的编号起始,有的厂家可能为1组,有得厂家可能有好几组
u16 ngpio;//表示这一组有几个gpio口用于参数检查,来源于chip->ngpio
const char *label;
void *data;
struct list_head list;
...
};
可以从设备树看出是好几组的还是1组的,驱动只调用1次的就为1组,base一般就是0开始。
struct gpio_desc {//主要记录每个管脚的状态,是不是被用于中断,是否被export by sysfs,and 是否 out
struct gpio_device *gdev;
unsigned long flags;
...
/* Connection label */
const char *label;
/* Name of the GPIO */
const char *name;
};
struct gpio_chip {//chip是干活的,他有很多方法,设置方向啊输出值啊等。
const char *label;
struct gpio_device *gpiodev;
struct device *parent;
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,
...
}
struct list_head gpio_devices;//gpio_device拷这个链表串起来的
重要内部接口
struct gpio_desc *gpio_to_desc(unsigned gpio)//将gpionum转化为一个gpio描述并检查有效性
static struct gpio_desc *gpio_name_to_desc(const char * const name)//根据那么获取的desc
int desc_to_gpio(const struct gpio_desc *desc)//desc转化为gpio num
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
gpiochip_add_data_with_key
该函数根据chip信息alloc struct gpio_device对象,以及创建gdev->descs[chip->ngpio]数组
int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
{
int base = chip->base;
gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
gdev->dev.bus = &gpio_bus_type;
gdev->chip = chip;
chip->gpiodev = gdev;
...
dev_set_name(&gdev->dev, "gpiochip%d", gdev->id);
device_initialize(&gdev->dev);
dev_set_drvdata(&gdev->dev, gdev);
gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
gdev->ngpio = chip->ngpio;
gdev->data = data;
gdev->base = base;
status = gpiodev_add_to_list(gdev);//将gpio_device串起来
for (i = 0; i < chip->ngpio; i++) {
struct gpio_desc *desc = &gdev->descs[i];
desc->gdev = gdev;
desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
}
if (gpiolib_initialized) {
status = gpiochip_setup_dev(gdev);
if (status)
goto err_remove_chip;
}
}
gpiochip_add-》gpiochip_add_data(chip, NULL);-》gpiochip_add_data_with_key(chip, data, NULL, NULL)
调用一次chip产生一个gpio_device,一个gpio_device拥有chip->ngpio个gpio_desc
比如hisi--好几个chip每个chip一个dev,每个dev 8个gpio_desc
struct gpio_chip一般会在各大平台的gpio控制器驱动的probe中创建该对象,并且做初始化,
最后调用gpiochip_add从而引发device的创建。
gpiodev_add_to_list
int gpiodev_add_to_list(struct gpio_device *gdev)
吧gdev放到合适地方,gpionum从小到大排序
gpio如何统一
注册函数
由上分析后再回国头来看,request根据gpio编号获得这个管脚的desc,
kernel\drivers\gpio\gpiolib-legacy.c
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc = gpio_to_desc(gpio);
/* Compatibility: assume unavailable "valid" GPIOs will appear later */
if (!desc && gpio_is_valid(gpio))
return -EPROBE_DEFER;
return gpiod_request(desc, label);
}
static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) //可以看出设置管脚输出0 1 都是chip去干的
{
struct gpio_chip *chip;
chip = desc->gdev->chip;
trace_gpio_value(desc_to_gpio(desc), 0, value);
chip->set(chip, gpio_chip_hwgpio(desc), value);
}
example nt平台的注册
从gpio驱动控制器寄存器角度如何把gpio寄存器和gpiolib联系起来的
比如nt平台设备树注册引发驱动probe
struct nvt_gpio_chip {
struct device *dev;
unsigned int irq_base; /* Shared IRQ */
unsigned int irq_offset; /* Extended offset */
struct irq_chip irq_chip;
struct gpio_chip gpio_chip; /* To abstract gpio controller */
...
};
static int nvt_gpio_probe(struct platform_device *pdev)
{
nvt_gpio_chip_ptr = kzalloc(sizeof(struct nvt_gpio_chip), GFP_KERNEL);
nvt_gpio_chip_ptr->gpio_chip.get = nvt_gpio_get;//这块就是nt驱动操作寄存器的函数
nvt_gpio_chip_ptr->gpio_chip.set = nvt_gpio_set;
nvt_gpio_chip_ptr->gpio_chip.direction_input = nvt_gpio_dir_input;
nvt_gpio_chip_ptr->gpio_chip.direction_output = nvt_gpio_dir_output;
nvt_gpio_chip_ptr->gpio_chip.get_direction = nvt_gpio_get_dir;
nvt_gpio_chip_ptr->gpio_chip.ngpio = NVT_GPIO_NUMBER;//320
nvt_gpio_chip_ptr->gpio_chip.base = 0;
...
ret = gpiochip_add(&nvt_gpio_chip_ptr->gpio_chip);//gpiochip_add引发struct gpio_device对象创建
说明
1. 不同厂家可能处理不一样,nt平台吧所有gpio看成一个chip,所以驱动chip 的base从base 开始ngpio=320个
而有的厂家比如hisi gpioA为一个chip,gpioB为一个chip所以他们的base和ngpio都不一样,这个地方需要注意。