居然快一年没有更新博客了,近段时间看了下以前的一些笔记,发现做过的项目,学习的知识都忘了差不多,其实还是应该抽点时间出来记录下。
当然先列出参考文章:
http://blog.chinaunix.net/uid-27717694-id-3624294.html GPIO的驱动模型
http://www.wowotech.net/gpio_subsystem/io-port-control.html linux内核中的GPIO系统之(1):软件框架
使用芯片平台 mdm9x07.
GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq...然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[].当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数
表示一个gpio口,含对应的gpio_chip.
对于每一个gpio,都有一个gpio描述符,这个描述符包含了这个gpio所属的控制器即chip和一些标志,label等
gpio描述符
struct gpio_desc {
struct gpio_chip *chip;
unsigned long flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0 //GPIO 申请的标志,已申请的话该标志是1,否则是0
#define FLAG_IS_OUT 1
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 6 /* value has active low */
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define ID_SHIFT 16 /* add new flags before this one */
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
const char *label;
};
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; --- 采用了一个具有ARCH_NR_GPIOS大小的gpio描述符数组。这个描述符数组便代表了系统所有的gpio
#define ARCH_NR_GPIOS 512 --- 即系统现在有144个GPIO口
通过这个结构抽象化所有的GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO
struct gpio_chip
{
const char *label;
struct device *dev;
struct module *owner;
struct list_head list;
int (*request)(struct gpio_chip *chip,unsigned offset); //请求gpio
void (*free)(struct gpio_chip *chip,unsigned offset); //释放gpio
int (*get_direction)(struct gpio_chip *chip,unsigned offset); //获取方向
int (*direction_input)(struct gpio_chip *chip,unsigned offset); //配置gpio为输入,返回当前gpio状态
int (*direction_output)(struct gpio_chip *chip,unsigned offset, int value); //配置gpio为输出,并设置为value
int (*get)(struct gpio_chip *chip,unsigned offset); //获取gpio的状态
void (*set)(struct gpio_chip *chip,unsigned offset, int value); //设置gpio为value值
int (*set_debounce)(struct gpio_chip *chip,unsigned offset,unsigned debounce); //设置消抖动时间,尤其是gpio按键时有用
int (*to_irq)(struct gpio_chip *chip,unsigned offset); //把gpio号转换为中断号
void (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);
int base; // 这个gpio控制器的gpio开始编号
u16 ngpio; //这个gpio控制器说控制的gpio数
struct gpio_desc *desc;
const char *const *names;
bool can_sleep;
bool irq_not_threaded;
bool exported;
#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;
#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
#ifdef CONFIG_PINCTRL
struct list_head pin_ranges;
#endif
}
开始一些有用的命令了
cat /sys/kernel/debug/gpio
这个命令可以得到全部GPIO的状态
具体代码分析如下:
gpiolib.c
static int __init gpiolib_debugfs_init(void)
(void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,NULL, NULL, &gpiolib_operations);
static const struct file_operations gpiolib_operations = {
.owner = THIS_MODULE,
.open = gpiolib_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int gpiolib_open(struct inode *inode, struct file *file)
return seq_open(file, &gpiolib_seq_ops);
static const struct seq_operations gpiolib_seq_ops = {
.start = gpiolib_seq_start,
.next = gpiolib_seq_next,
.stop = gpiolib_seq_stop,
.show = gpiolib_seq_show,
};
static int gpiolib_seq_show(struct seq_file *s, void *v)
struct gpio_chip *chip = v;
seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,chip->base, chip->base + chip->ngpio - 1); --- 即 GPIOs 0-79
dev = chip->dev;
seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",dev_name(dev)); --- 即 platform/1000000.pinctrl
seq_printf(s, ", %s", chip->label); --- 即 , 1000000.pinctrl
seq_printf(s, ":\n"); --- 即 GPIOs 0-79, platform/1000000.pinctrl, 1000000.pinctrl:
chip->dbg_show(s, chip);
Pinctrl-msm.c (drivers\pinctrl\qcom)
static struct gpio_chip msm_gpio_template = {
.direction_input = msm_gpio_direction_input,
.direction_output = msm_gpio_direction_output,
.get = msm_gpio_get,
.set = msm_gpio_set,
.request = msm_gpio_request,
.free = msm_gpio_free,
.dbg_show = msm_gpio_dbg_show,
};
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
for (i = 0; i < chip->ngpio; i++, gpio++)
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
static void msm_gpio_dbg_show_o