Linux GPIO子系统代码分析教程
struct gpio\_desc {
struct gpio\_device *gdev; //GPIO设备
unsigned long flags; //引脚对应的标志
\#define FLAG\_REQUESTED 0 // 引脚被已被请求
\#define FLAG\_IS\_OUT 1 // 引脚是输出状态
\#define FLAG\_EXPORT 2
\#define FLAG\_SYSFS 3
\#define FLAG\_ACTIVE\_LOW 6
\#define FLAG\_OPEN\_DRAIN 7
\#define FLAG\_OPEN\_SOURCE 8
\#define FLAG\_USED\_AS\_IRQ 9
\#define FLAG\_IS\_HOGGED 11
const char *label; //链接标志
const char *name;
};
struct gpio\_device {
int id; //GPIO芯片的数字ID号
struct device dev; //对应的设备结构体
struct cdev chrdev; //对应的字符设备
struct device *mockdev;
struct module *owner;
struct gpio\_chip *chip; //gpio芯片
struct gpio\_desc *descs; //引脚描述符指针
int base; //gpio的起始号码
u16 ngpio; //管理的GPIO数量
char *label; //标签数据
void *data; //驱动程序分配的数据
struct list\_head list;
\#ifdef CONFIG\_PINCTRL
struct list\_head pin\_ranges; //定义一个引脚范围的链表
\#endif
};
struct gpio\_chip {
const char *label;
struct gpio\_device *gpiodev; //指向GPIO设备
struct device *parent; //GPIO的父设备
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);
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\_debounce)(struct gpio\_chip *chip,
unsigned offset,
unsigned debounce);
int (*set\_single\_ended)(struct gpio\_chip *chip,
unsigned offset,
enum single\_ended\_mode mode);
int (*to\_irq)(struct gpio\_chip *chip,
unsigned offset);
void (*dbg\_show)(struct seq\_file *s,
struct gpio\_chip *chip);
int base; //引脚的起始编号
u16 ngpio; //芯片支持的GPIO数量
const char *const *names;//对应的名字
bool can\_sleep; //是否睡眠
bool irq\_not\_threaded;
\#if IS\_ENABLED(CONFIG\_GPIO\_GENERIC)
unsigned long (*read\_reg)(void \_\_iomem *reg);
void (*write\_reg)(void \_\_iomem *reg, unsigned long data);
unsigned long (*pin2mask)(struct gpio\_chip *gc, unsigned int pin); //该回调返回正确的GPIO对应掩码
void \_\_iomem *reg\_dat; //数据寄存器
void \_\_iomem *reg\_set; //置位寄存器
void \_\_iomem *reg\_clr; //置零寄存器
void \_\_iomem *reg\_dir; //方向寄存器
int bgpio\_bits; //对应的bit
spinlock\_t bgpio\_lock;
unsigned long bgpio\_data;
unsigned long bgpio\_dir;
\#endif
\#ifdef CONFIG\_GPIOLIB\_IRQCHIP //支持中断
struct irq\_chip *irqchip; //中断芯片
struct irq\_domain *irqdomain; //中断映射的区域
unsigned int irq\_base; //中断的起始号
irq\_flow\_handler\_t irq\_handler;//中断处理函数
unsigned int irq\_default\_type; //中断默认的类型
int irq\_parent;
bool irq\_need\_valid\_mask; //中断是否需要中断有效掩码
unsigned long *irq\_valid\_mask;
struct lock\_class\_key *lock\_key;
\#endif
\#if defined(CONFIG\_OF\_GPIO) //对应设备树的操作
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
};
static inline int gpiochip\_add(struct gpio\_chip *chip)
{
return gpiochip\_add\_data(chip, NULL);
}
int gpiochip\_add\_data(struct gpio\_chip *chip, void *data)
{
unsigned long flags;
int status = 0;
unsigned i;
int base = chip->base; //芯片对应的起始芯片标号
struct gpio\_device *gdev;
gdev = kzalloc(sizeof(*gdev), GFP\_KERNEL);
if (!gdev)
return -ENOMEM;
gdev->dev.bus = &gpio\_bus\_type;
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 (chip->of\_node)
gdev->dev.of\_node = chip->of\_node;
\#endif
gdev->id = ida\_simple\_get(&gpio\_ida, 0, 0, GFP\_KERNEL);
if (gdev->id < 0) {
status = 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)
gdev->owner = chip->owner;
else
gdev->owner = THIS\_MODULE;
gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP\_KERNEL);
if (!gdev->descs) {
status = -ENOMEM;
goto err\_free\_gdev;
}
if (chip->ngpio == 0) {
chip\_err(chip, "tried to insert a GPIO chip with zero lines\n");
status = -EINVAL;
goto err\_free\_descs;
}
if (chip->label)
gdev->label = kstrdup(chip->label, GFP\_KERNEL);
else
gdev->label = kstrdup("unknown", GFP\_KERNEL);
if (!gdev->label) {
status = -ENOMEM;
goto err\_free\_descs;
}
gdev->ngpio = chip->ngpio;
gdev->data = data;
spin\_lock\_irqsave(&gpio\_lock, flags);
if (base < 0) {
base = gpiochip\_find\_base(chip->ngpio);
if (base < 0) {
status = base;
spin\_unlock\_irqrestore(&gpio\_lock, flags);
goto err\_free\_label;
}
chip->base = base;
}
gdev->base = base;
status = gpiodev\_add\_to\_list(gdev);
if (status) {
spin\_unlock\_irqrestore(&gpio\_lock, flags);
goto err\_free\_label;
}
spin\_unlock\_irqrestore(&gpio\_lock, flags);
for (i = 0; i < chip->ngpio; i++) {
struct gpio\_desc *desc = &gdev->descs[i];
desc->gdev = gdev;
if (chip->get\_direction) {
int dir = chip->get\_direction(chip, i);
if (!dir)
set\_bit(FLAG\_IS\_OUT, &desc->flags);
} else if (!chip->direction\_input) {
set\_bit(FLAG\_IS\_OUT, &desc->flags);
}
}
\#ifdef CONFIG\_PINCTRL
INIT\_LIST\_HEAD(&gdev->pin\_ranges);
\#endif
status = gpiochip\_set\_desc\_names(chip);
if (status)
goto err\_remove\_from\_list;
status = gpiochip\_irqchip\_init\_valid\_mask(chip);
if (status)
goto err\_remove\_from\_list;
status = of\_gpiochip\_add(chip);
if (status)
goto err\_remove\_chip;
acpi\_gpiochip\_add(chip);
if (gpiolib\_initialized) {
status = gpiochip\_setup\_dev(gdev);
if (status)
goto err\_remove\_chip;
}
return 0;
err\_remove\_chip:
acpi\_gpiochip\_remove(chip);
gpiochip\_free\_hogs(chip);
of\_gpiochip\_remove(chip);
gpiochip\_irqchip\_free\_valid\_mask(chip);
err\_remove\_from\_list:
spin\_lock\_irqsave(&gpio\_lock, flags);
list\_del(&gdev->list);
spin\_unlock\_irqrestore(&gpio\_lock, flags);
err\_free\_label:
kfree(gdev->label);
err\_free\_descs:
kfree(gdev->descs);
err\_free\_gdev:
ida\_simple\_remove(&gpio\_ida, gdev->id);
pr\_err("%s: GPIOs %d..%d (%s) failed to register\n", \_\_func\_\_,
gdev->base, gdev->base + gdev->ngpio - 1,
chip->label ? : "generic");
kfree(gdev);
return status;
}
\#define GPIOF\_DIR\_OUT (0 << 0)
\#define GPIOF\_DIR\_IN (1 << 0)
\#define GPIOF\_INIT\_LOW (0 << 1)
\#define GPIOF\_INIT\_HIGH (1 << 1)
\#define GPIOF\_IN (GPIOF\_DIR\_IN)
\#define GPIOF\_OUT\_INIT\_LOW (GPIOF\_DIR\_OUT | GPIOF\_INIT\_LOW)
\#define GPIOF\_OUT\_INIT\_HIGH (GPIOF\_DIR\_OUT | GPIOF\_INIT\_HIGH)
\#define GPIOF\_ACTIVE\_LOW (1 << 2)
\#define GPIOF\_OPEN\_DRAIN (1 << 3)
\#define GPIOF\_OPEN\_SOURCE (1 << 4)
\#define GPIOF\_EXPORT (1 << 5)
\#define GPIOF\_EXPORT\_CHANGEABLE (1 << 6)
\#define GPIOF\_EXPORT\_DIR\_FIXED (GPIOF\_EXPORT)
\#define GPIOF\_EXPORT\_DIR\_CHANGEABLE (GPIOF\_EXPORT | GPIOF\_EXPORT\_CHANGEABLE)
struct gpio {
unsigned gpio; //GPIO引脚号
unsigned long flags; //使用以上GPIOF\_*的宏来标记引脚的属性
const char *label; //用来描述引脚的字符串
};
static inline int gpio\_get\_value(unsigned int gpio)
{
return \_\_gpio\_get\_value(gpio);
}
static inline int \_\_gpio\_get\_value(unsigned gpio)
{
return gpiod\_get\_raw\_value(gpio\_to\_desc(gpio));
}
nt gpiod\_get\_raw\_value(const struct gpio\_desc *desc)
{
VALIDATE\_DESC(desc);
WARN\_ON(desc->gdev->chip->can\_sleep);
return \_gpiod\_get\_raw\_value(desc);
}
static int \_\_maybe\_unused gpio\_chip\_hwgpio(const struct gpio\_desc *desc)
{
return desc - &desc->gdev->descs[0];
}
static int \_gpiod\_get\_raw\_value(const struct gpio\_desc *desc)
{
*struct gpio\_chip *chip;
int offset;
int value;*
chip = desc->gdev->chip; //从描述符找到GPIO芯片
offset = gpio\_chip\_hwgpio(desc); //对应引脚在该芯片上的引脚号偏移
**value = chip->get ? chip->get(chip, offset) : -EIO;//调用回调函数获取GPIO的引脚值
value = value < 0 ? value : !!value;
trace\_gpio\_value(desc\_to\_gpio(desc), 1, value);
return value;
}
**
static inline void gpio\_set\_value(unsigned int gpio, int value)
{
\_\_gpio\_set\_value(gpio, value);
}
void gpiod\_set\_raw\_value(struct gpio\_desc *desc, int value)
{
VALIDATE\_DESC\_VOID(desc);
WARN\_ON(desc->gdev->chip->can\_sleep);
\_gpiod\_set\_raw\_value(desc, value);
}
static void \_gpiod\_set\_raw\_value(struct gpio\_desc *desc, bool value)
{
struct gpio\_chip *chip;
chip = desc->gdev->chip;
trace\_gpio\_value(desc\_to\_gpio(desc), 0, value);
if (test\_bit(FLAG\_OPEN\_DRAIN, &desc->flags))
\_gpio\_set\_open\_drain\_value(desc, value);
else if (test\_bit(FLAG\_OPEN\_SOURCE, &desc->flags))
\_gpio\_set\_open\_source\_value(desc, value);
else
chip->set(chip, gpio\_chip\_hwgpio(desc), value); //设置对应的输出值
}
static inline int gpio\_cansleep(unsigned int gpio)
{
return \_\_gpio\_cansleep(gpio);
}
static inline int gpio\_to\_irq(unsigned int gpio)
{
return \_\_gpio\_to\_irq(gpio);
}
static inline int irq\_to\_gpio(unsigned int irq)
{
return -EINVAL;
}
\#endif
struct device;
int devm\_gpio\_request(struct device *dev, unsigned gpio, const char *label);
int devm\_gpio\_request\_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label);
void devm\_gpio\_free(struct device *dev, unsigned int gpio);
\#ifndef ARCH\_NR\_GPIOS
#if defined(CONFIG\_ARCH\_NR\_GPIO) && CONFIG\_ARCH\_NR\_GPIO > 0
#define ARCH\_NR\_GPIOS CONFIG\_ARCH\_NR\_GPIO
#else
#define ARCH\_NR\_GPIOS 512
#endif
\#endif
static inline bool gpio\_is\_valid(int number)
{
return number >= 0 && number < ARCH\_NR\_GPIOS;
}
struct device;
struct gpio;
struct seq\_file;
struct module;
struct device\_node;
struct gpio\_desc;
static inline struct gpio\_chip *gpio\_to\_chip(unsigned gpio)
{
return gpiod\_to\_chip(gpio\_to\_desc(gpio));
}
extern int gpio\_request(unsigned gpio, const char *label);
extern void gpio\_free(unsigned gpio);
static inline int gpio\_direction\_input(unsigned gpio)
{
return gpiod\_direction\_input(gpio\_to\_desc(gpio));
}
static inline int gpio\_direction\_output(unsigned gpio, int value)
{
return gpiod\_direction\_output\_raw(gpio\_to\_desc(gpio), value);
}
static inline int gpio\_set\_debounce(unsigned gpio, unsigned debounce)
{
return gpiod\_set\_debounce(gpio\_to\_desc(gpio), debounce);
}
static inline int gpio\_get\_value\_cansleep(unsigned gpio)
{
return gpiod\_get\_raw\_value\_cansleep(gpio\_to\_desc(gpio));
}
static inline void gpio\_set\_value\_cansleep(unsigned gpio, int value)
{
return gpiod\_set\_raw\_value\_cansleep(gpio\_to\_desc(gpio), value);
}
static inline int \_\_gpio\_get\_value(unsigned gpio)
{
return gpiod\_get\_raw\_value(gpio\_to\_desc(gpio));
}
static inline void \_\_gpio\_set\_value(unsigned gpio, int value)
{
return gpiod\_set\_raw\_value(gpio\_to\_desc(gpio), value);
}
static inline int \_\_gpio\_cansleep(unsigned gpio)
{
return gpiod\_cansleep(gpio\_to\_desc(gpio));
}
static inline int \_\_gpio\_to\_irq(unsigned gpio)
{
return gpiod\_to\_irq(gpio\_to\_desc(gpio));
}
extern int gpio\_request\_one(unsigned gpio, unsigned long flags, const char *label);
extern int gpio\_request\_array(const struct gpio *array, size\_t num);
extern void gpio\_free\_array(const struct gpio *array, size\_t num);
static inline int gpio\_export(unsigned gpio, bool direction\_may\_change)
{
return gpiod\_export(gpio\_to\_desc(gpio), direction\_may\_change);
}
int gpiod\_export(struct gpio\_desc *desc, bool direction\_may\_change)
{
struct gpio\_chip *chip;
struct gpio\_device *gdev;
struct gpiod\_data *data;
unsigned long flags;
int status;
const char *ioname = NULL;
struct device *dev;
int offset;
if (!gpio\_class.p) {
pr\_debug("%s: called too early!\n", \_\_func\_\_);
return -ENOENT;
}
if (!desc) {
pr\_debug("%s: invalid gpio descriptor\n", \_\_func\_\_);
return -EINVAL;
}
gdev = desc->gdev;
chip = gdev->chip;
mutex\_lock(&sysfs\_lock);
if (!chip || !gdev->mockdev) {
status = -ENODEV;
goto err\_unlock;
}
spin\_lock\_irqsave(&gpio\_lock, flags);
if (!test\_bit(FLAG\_REQUESTED, &desc->flags) ||
test\_bit(FLAG\_EXPORT, &desc->flags)) {
spin\_unlock\_irqrestore(&gpio\_lock, flags);
gpiod\_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
\_\_func\_\_,
test\_bit(FLAG\_REQUESTED, &desc->flags),
test\_bit(FLAG\_EXPORT, &desc->flags));
status = -EPERM;
goto err\_unlock;
}
spin\_unlock\_irqrestore(&gpio\_lock, flags);
data = kzalloc(sizeof(*data), GFP\_KERNEL);
if (!data) {
status = -ENOMEM;
goto err\_unlock;
}
data->desc = desc;
mutex\_init(&data->mutex);
if (chip->direction\_input && chip->direction\_output)
data->direction\_can\_change = direction\_may\_change;
else
data->direction\_can\_change = false;
offset = gpio\_chip\_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
dev = device\_create\_with\_groups(&gpio\_class, &gdev->dev,
MKDEV(0, 0), data, gpio\_groups,
ioname ? ioname : "gpio%u",
desc\_to\_gpio(desc));
if (IS\_ERR(dev)) {
status = PTR\_ERR(dev);
goto err\_free\_data;
}
set\_bit(FLAG\_EXPORT, &desc->flags);
mutex\_unlock(&sysfs\_lock);
return 0;
err\_free\_data:
kfree(data);
err\_unlock:
mutex\_unlock(&sysfs\_lock);
gpiod\_dbg(desc, "%s: status %d\n", \_\_func\_\_, status);
return status;
}
static inline int gpio\_export\_link(struct device *dev, const char *name,
unsigned gpio)
{
return gpiod\_export\_link(dev, name, gpio\_to\_desc(gpio));
}
static inline void gpio\_unexport(unsigned gpio)
{
gpiod\_unexport(gpio\_to\_desc(gpio));
}