简介:
gpio源自GPIO控制器, 通常一个芯片会有多个GPIO控制器. GPIO驱动就是GPIO控制器驱动. 这部分驱动通常由
芯片原厂编写,不同芯片厂商的GPIO控制器差异很大, 但是他们基于linux内核会相同的架构编写,实现方式大同小异.
对于普通开发者来说,只需要知道怎么使用(申请,释放,设置输入输出...)就可以了,但是了解GPIO控制器驱动实现方式对深入理解
GPIO是有帮助的.
首先看下GPIO控制器驱动是如何编写的,然后介绍驱动中如何使用GPIO,最后介绍sysfs,proc,debugfs下的GPIO相关内容(如果有的话.)
1. gpio控制器驱动
struct gpio_chip 代表一个GPIO控制器(include/linux/gpio/driver.h), 定义如下:
1.1 gpio_chip 结构
/**
* struct gpio_chip 是GPIO控制器的抽象, 代表一个GPIO控制器.
*/
struct gpio_chip {
const char *label; //标签
struct gpio_device *gpiodev; //gpio_chip 关联的gpio_deivce, 一个gpiochip 就是一个gpio_device.
struct device *parent; // gpio_device的父设备, 通常是注册这个chip设备.
struct module *owner; // 所有者
/**
* GPIO控制器驱动要实现的GPIO操作函数. 当然不必实现全部的功能.
*/
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_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);
/**
* 一个gpio_chip 管理一组GPIO, 系统中所有GPIO拥有唯一的编号.
* base:指定当前gpio_chip 管理的这组GPIO的初始编号,=-1 表示使用动态分配的初始编号
* ngpio: 这ge gpio_chip 管理的GPIO数量.
*/
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);
unsigned long (*pin2mask)(struct gpio_chip *gc, unsigned int pin);
void __iomem *reg_dat;
void __iomem *reg_set;
void __iomem *reg_clr;
void __iomem *reg_dir;
int bgpio_bits;
spinlock_t bgpio_lock;
unsigned long bgpio_data;
unsigned long bgpio_dir;
#endif
/*由GPIO管理中断,处理中断事件.*/
#ifdef CONFIG_GPIOLIB_IRQCHIP
/*
* With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
* to handle IRQs for most practical cases.
*/
/**
* @irq:
*
* Integrates interrupt chip functionality with the GPIO chip. Can be
* used to handle IRQs for most practical cases.
*/
struct gpio_irq_chip irq;
#endif
/**
* 使用GPIO 设备树, 如果开启则可以使用
* of_get_name_gpio... 等等 of相关函数
*/
#if defined(CONFIG_OF_GPIO)
/*
* If CONFIG_OF is enabled, then all GPIO controllers described in the
* device tree automatically may have an OF translation
*/
/**
* @of_node:
* GPIO 控制器的设备树节点.
*/
struct device_node *of_node;
/**
* @of_gpio_n_cells:
* 描述一个GPIO(不是gpio_chip)用到的关键字数量,
* Number of cells used to form the GPIO specifier.
*/
unsigned int of_gpio_n_cells;
/**
* @of_xlate:
*
* Callback to translate a device tree GPIO specifier into a chip-
* relative GPIO number and flags.
*/
int (*of_xlate)(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags);
#endif
};
1.2 注册一个gpio_chip
驱动中只需要填充一个 struct chio_chip结构体然后调用注册函数即可,重点是注册函数做了什么.
static int sprd_gpio_probe(struct platform_device *pdev)
{
struct gpio_irq_chip *irq;
struct sprd_gpio *sprd_gpio;
struct resource *res;
int ret;
sprd_gpio = devm_kzalloc(&pdev->dev, sizeof(*sprd_gpio), GFP_KERNEL);
if (!sprd_gpio)
return -ENOMEM;
sprd_gpio->irq = platform_get_irq(pdev, 0);
if (sprd_gpio->irq < 0) {
dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n");
return sprd_gpio->irq;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0)