GPIO相关的内核参考文档为Documentation/gpio.txt

GPIO相应的API

标准GPIO API

这些API的头文件定义于include/linux/gpio.h中,实际位于include/asm-generic/gpio.h中

bool gpio_is_valid(int number);
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int __gpio_get_value(unsigned gpio);
void __gpio_set_value(unsigned gpio, int value);

int gpio_export(unsigned gpio, bool direction_may_change);
void gpio_unexport(unsigned gpio);

int __gpio_cansleep(unsigned gpio);
int gpio_get_value_cansleep(unsigned gpio);
void gpio_set_value_cansleep(unsigned gpio, int value);

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_array(const struct gpio *array, size_t num);

中断部分的API

中断函数的原型实现在kernel/irq目录下

int __gpio_to_irq(unsigned gpio);
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
void free_irq(unsigned int irq, void *dev_id);
int irq_set_irq_type(unsigned int irq, unsigned int type);
void enable_irq(unsigned int irq);
void disable_irq(unsigned int irq);
int __disable_irq_nosync(unsigned int irq);

使用GPIO步骤

  1. include header
    #include <linux/gpio.h>
  2. check valid (optional)
    每一个chip上的gpio数量是有限制的(而且gpio号码一定>=0),为了防止指定的gpio号码是错的,可以先使用gpio_is_valid来检查。
    int gpio_is_valid(int number);//return true if valid.
  3. request gpio (optional, but recommended)
    gpio_request可以检查gpio number是否超出范围或小于0及指定的gpio是否正在使用,因为有时候别的地方也控制着同一个gpio可能会发生预期外的结果。

    /**
    * return -EINVAL if GPIO is not valid(same as gpio_is_valid)
    * return -EBUSY if GPIO is already used
    * return 0 if GPIO is fine to use
    * 因此我們只要檢查回傳質是否>=0就可以判斷是否可用。
    * 第一個參數是填入GPIO的號碼、第二個參數是想要對這個GPIO的命名。
    * $ cat /sys/kernel/debug/gpio就可以看到 
    */
    int gpio_request(unsigned gpio, const char *label);
    
  4. configure gpio

    /* set as input or output, returning 0 or negative errno */
    int gpio_direction_input(unsigned gpio);
    int gpio_direction_output(unsigned gpio, int value);
    
  5. access gpio

     /* GPIO INPUT:  return zero or nonzero */
    int gpio_get_value(unsigned gpio);
    
    /* GPIO OUTPUT */
    void gpio_set_value(unsigned gpio, int value);
    
  6. free gpio
    当使用完GPIO之后利用gpio_free来释放GPIO
    int gpio_free(unsigned gpio);


GPIO源码架构分析

gpio相应的API其实调用的是注册的struct gpio_chip中的一些方法,来看下struct gpio_chip这个结构体,

struct gpio_chip {
        const char              *label;
        struct device           *dev;
        struct module           *owner;
        struct list_head        list;

        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                     (*get)(struct gpio_chip *chip, unsigned offset);
        int                     (*direction_output)(struct gpio_chip *chip, unsigned offset, int value);
        int                     (*set_debounce)(struct gpio_chip *chip, unsigned offset, unsigned debounce);
        void                    (*set)(struct gpio_chip *chip, unsigned offset, int value);
        int                     (*to_irq)(struct gpio_chip *chip, unsigned offset);
        void                    (*dbg_show)(struct seq_file *s, struct gpio_chip *chip);
        int                     base;
        u16                     ngpio;
        struct gpio_desc        *desc;
        const char              *const *names;
        unsigned                can_sleep:1;
        unsigned                exported:1;

所以要使用gpio相应的API,必须事先注册一个struct gpio_chip结构体,并实现其中的方法,如下是一个例子,

static struct gpio_chip template_chip = {
        .label                  = "wm8994",
        .owner                  = THIS_MODULE,
        .request                = wm8994_gpio_request,
        .direction_input        = wm8994_gpio_direction_in,
        .get                    = wm8994_gpio_get,
        .direction_output       = wm8994_gpio_direction_out,
        .set                    = wm8994_gpio_set,
        .to_irq                 = wm8994_gpio_to_irq,
        .dbg_show               = wm8994_gpio_dbg_show,
        .can_sleep              = 1,
};

另外需要说明一点是在struct gpio_chip结构体的这些函数中,既可以直接去操作gpio相应的寄存器,也可以通过i2c等接口去操作gpio,也可以调用pinctrl中提供的一些操作gpio的方法,总之,这个结构体的这些函数必须实现能够操作gpio。

Logo

更多推荐