0
点赞
收藏
分享

微信扫一扫

GPIO子系统

静悠 2022-10-31 阅读 46


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);

  1. 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);

  1. access gpio

/* GPIO INPUT:  return zero or nonzero */
int gpio_get_value(unsigned gpio);

/* GPIO OUTPUT */
void gpio_set_value(unsigned gpio, int value);

  1. 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。


举报

相关推荐

0 条评论