Linux下GPIO驱动模型

转载地址:http://blog.sina.com.cn/s/blog_5ef638bc0100rzve.html


GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,当然你也可以选择不用这个模型实现gpio。具体见说明文档Documention/gpio.txt。


下面粗略说一下这个模型关键的数据结构和函数:
  为了给不同GPIO控制器提供一个统一的编程接口,内核提供了一个可选择的实现架构。这个架构被称作"gpiolib".
  在这个架构下,每个GPIO控制器被抽象成“struct gpio_chip",这里GPIO控制器的所有常规信息:
-设定传输方向(输入/输出)的函数
-读写GPIO值的函数
-是否调用可睡眠的函数的flag
-可选择的用来调试的输出(dump method)
-用来诊断的标志
还有一些来自device.platform_data等与体系相关的数据,比如gpio起始号和多少可用的gpio号。
  向内核注册gpio_chip是调用gpiochip_add(),注销时调用gpiochip_remove()。
  通常gpio_chip是被包含在一个体系相关的结构体内,这个结构体里有一些与gpio状态相关的成员,比如如何寻址,电源管理等等。
-------------------------------------------------
    为了支持gpio实现框架(已经说过,是可选择的),Kconfig里应该选择ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并且让<asm/gpio.h>包含<asm-generic/gpio.h>(只要包含就可以,直接间接无所谓)并且定义三个函数:gpio_get_value(), gpio_set_value(), and gpio_cansleep().通常还需要提供ARCH_NR_GPIOS的值(代表有几个GPIO分组)。
    上面3个函数实际上要调用底层函数,自己实现后就可以用gpio的架构了。
  #define gpio_get_value        __gpio_get_value
  #define gpio_set_value        __gpio_set_value
  #define gpio_cansleep         __gpio_cansleep
     你也可以不这么实现,可以用inline函数逻辑优化直接SOC-based GPIOs,这样就避免了繁复调用花费的开销(有兴趣可以深入研究)。
     对于SOC,与平台相关的代码为每组gpio注册一个gpio_chip,里面是参照硬件原理图和数据手册定义的。通常在平台初始化时gpio也要初始化,通过调用arch_initcall或者更早的函数,他们也可作为IRQ来用。
     还有对应外部GPIO控制器的描诉,比如I2C和SPI扩展器,ASICs,FPGAs等,当加载模块时,初始化函数要分配好相应的数据,然后probe()会调用gpiochip_add()注册(没详细看,具体见文档)。
--------------------------------------------------
     下面是转载别人的理解和具体实现(具体平台可能不一样,只作理解参考):
GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq... 然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[].
当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数。


寄存器读写函数:   __raw_writel()   __raw_writeb()   __raw_readl()   __raw_readb()

gpio是一组可控件的脚,由多个寄存器同时控制。通过设置对应的寄存器可以达到设置GPIO口对应状态与功能。
数据状态,输入输出方向,清零,中断(那个边沿触发), 一般是一组(bank)一组的。
//
注册方法:
1:struct gpio_chip: 表示一个gpio controller.通过这个结构抽象化所有的 GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO。
2: struct gpio_desc: 表示一个gpio口,含对应的 gpio_chip.
3: ARCH_NR_GPIOS:  与板相关的GPIO口数量,即是全局GPIO数组:static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
4: 注册 gpio_chip时,就是根据 chip 的数据 修改全局 GPIO数组中 gpio_desc 字段(chip, flags)。

//
首先 twl4030中的 GPIO模块: 在 twl4030的驱动注册时,probe中,生成了GPIO对应的 i2c_client 与 platform_device.
twl4030,当加载GPIO的驱动(匹配platform_device)时,首先进行对应的设置,GPIO设置。
然后设置结构: gpio_chip: twl_gpiochip: gpio_twl4030_pulls,pio_twl4030_debounce,
注册 之:ret = gpiochip_add(&twl_gpiochip);//添加到全局的 gpio_desc数组中。即是设置全局gpio_desc中这个gpio_chip对应的几个gpio的字段。

setup之:status = pdata->setup(&pdev->dev, pdata->gpio_base, TWL4030_GPIO_MAX);
setup(...) ==》 twl4030_mmc_init(mmc); //在添加完gpio后,进行探测MMC,然后注册之。Register MMC devices.

//
-------------------------------------------------
gpiolib架构会在/sys/class/gpio下提供用户编程接口,可以通过这个接口去控制gpio状态。(具体见文档)
-------------------------------------------------
最后注意,内核中存在对普通LED和BUTTON的GPIO架构,“leds-gpio" 和 "gpio_keys",用这个架构去实现LED和BUTTON而不是去直接控制GPIO,和内核会有更好的集成度。

-------------------------------------------------
struct gpio_desc {
struct gpio_chip *chip;
unsigned long flags;
#define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1
#define FLAG_RESERVED 2
#define FLAG_EXPORT 3
#define FLAG_SYSFS 4

#ifdef CONFIG_DEBUG_FS
const char *label;
#endif
};
**
 * struct gpio_chip - abstract a GPIO controller
 * @label: for diagnostics
 * @dev: optional device providing the GPIOs
 * @owner: helps prevent removal of modules exporting active GPIOs
 * @request: optional hook for chip-specific activation, such as
 * enabling module power and clock; may sleep
 * @free: optional hook for chip-specific deactivation, such as
 * disabling module power and clock; may sleep
 * @direction_input: configures signal "offset" as input, or returns error
 * @get: returns value for signal "offset"; for output signals this
 * returns either the value actually sensed, or zero
 * @direction_output: configures signal "offset" as output, or returns error
 * @set: assigns output value for signal "offset"
 * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
 * implementation may not sleep
 * @dbg_show: optional routine to show contents in debugfs; default code
 * will be used when this is omitted, but custom code can show extra
 * state (such as pullup/pulldown configuration).
 * @base: identifies the first GPIO number handled by this chip; or, if
 * negative during registration, requests dynamic ID allocation.
 * @ngpio: the number of GPIOs handled by this controller; the last GPIO
 * handled is (base + ngpio - 1).
 * @can_sleep: flag must be set iff get()/set() methods sleep, as they
 * must while accessing GPIO expander chips over I2C or SPI
 *
 * A gpio_chip can help platforms abstract various sources of GPIOs so
 * they can all be accessed through a common programing interface.
 * Example sources would be SOC controllers, FPGAs, multifunction
 * chips, dedicated GPIO expanders, and so on.
 *
 * Each chip controls a number of signals, identified in method calls
 * by "offset" values in the range 0..(@ngpio - 1).  When those signals
 * are referenced through calls like gpio_get_value(gpio), the offset
 * is calculated by subtracting @base from the gpio number.
 *
struct gpio_chip {
const char *label;
struct device *dev;
struct module *owner;

int (*request)(struct gpio_chip *chip,
unsigned offset);
void (*free)(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);
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;
unsigned can_sleep:1;
unsigned exported:1;
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值