//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)。
一、重点关注的相关的结构体:
gpiolib.c文件,被移植到driver/gpio/目录下。
structgpio_desc
{
structgpio_chip
*chip;
unsignedlong
flags;
#defineFLAG_REQUESTED
0
#defineFLAG_IS_OUT
1
#defineFLAG_RESERVED
2
#defineFLAG_EXPORT
3
#defineFLAG_SYSFS
4
#defineFLAG_TRIG_FALL
5
#defineFLAG_TRIG_RISE
6
#defineFLAG_ACTIVE_LOW
7
#defineID_SHIFT
16
#defineGPIO_FLAGS_MASK
((1 << ID_SHIFT) - 1)
#defineGPIO_TRIGGER_MASK
(BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
#ifdefCONFIG_DEBUG_FS
constchar
*label;
#endif
};
对于上面这个结构体,现在只关心structgpio_chip
*chip;
structgpio_chip {
constchar *label;
structdevice *dev;
structmodule *owner;
int (*request)(struct gpio_chip
*chip,
unsignedoffset);
void (*free)(struct gpio_chip
*chip,
unsignedoffset);
int (*direction_input)(struct gpio_chip
*chip,
unsignedoffset);
int (*get)(struct gpio_chip
*chip,
unsignedoffset);
int (*direction_output)(struct gpio_chip
*chip,
unsignedoffset, int
value);
int (*set_debounce)(struct gpio_chip
*chip,
unsignedoffset, unsigned
debounce);
void (*set)(struct gpio_chip
*chip,
unsignedoffset, int
value);
int (*to_irq)(struct gpio_chip
*chip,
unsignedoffset);
void (*dbg_show)(struct seq_file
*s,
structgpio_chip
*chip);
int base;
u16 ngpio;
constchar *const
*names;
unsigned can_sleep:1;
unsigned exported:1;
};
二、把目光转到龙芯自身的gpio文件。
在1b的内容是放在arch/mips/loongson/sb2f-board/gpio.c
staticstruct gpio_chip ls2f_chip =
{
.label = "ls2f",
.direction_input =
ls2f_gpio_direction_input,
.get =
ls2f_gpio_get_value,
.direction_output =
ls2f_gpio_direction_output,
.set =
ls2f_gpio_set_value,
.base = 0,
.ngpio =
STLS2F_N_GPIO,
};
staticint __init
ls2f_gpio_setup(void)
{
returngpiochip_add(&ls2f_chip);
}
arch_initcall(ls2f_gpio_setup);
arch_initcall函数在内核启动的时候被初始化。(详细情况,以后再写)
跟着调用了ls2f_gpio_setup
-> gpiochip_add
增加了ls2f_chip。
注意ls2f_chip里面的函数指针(我们姑且成为接口吧)已经在本文件(gpio.c里面实现。)
三、现在跳到gpiochip_add函数(在driver/gpio/gpiolib.c中)
intgpiochip_add(struct gpio_chip
*chip)
{
……
for(id = base; id < base + chip->ngpio;
id++) {
gpio_desc[id].chip=
chip;
……
}
……
}
上述的代码初始化了gpio_desc数组。在gpiolib.c中定义:
staticstruct gpio_desc
gpio_desc[ARCH_NR_GPIOS];
直到这里,gpio_desc已经可以和龙芯下面的函数接口关联起来!
四、在驱动中利用这些接口
如在驱动中调用函数:gpio_direction_output(57,0);
函数定义位gpiolib.c文件中
intgpio_direction_output(unsigned gpio, int
value)
{
……
status= chip->direction_output(chip, gpio,
value);
……
}
第三点已经说明了是如何关联起来的。于是相当于调用龙芯芯片下的函数:
staticint ls2f_gpio_direction_output(struct
gpio_chip *chip, unsigned gpio,int level)
{
u32temp;
u32mask;
if(gpio >=
STLS2F_N_GPIO)
return-EINVAL;
gpio_set_value(gpio,level);
if(gpio>= 32){
spin_lock(&gpio_lock);
mask= 1 << (gpio -
32);
temp=
LOONGSON_GPIOCFG1;
temp|= mask;
LOONGSON_GPIOCFG1=
temp;
temp=
LOONGSON_GPIOIE1;
temp&= (~mask);
LOONGSON_GPIOIE1=
temp;
spin_unlock(&gpio_lock);
}else{
spin_lock(&gpio_lock);
mask= 1 << gpio;
temp=
LOONGSON_GPIOCFG0;
temp|= mask;
LOONGSON_GPIOCFG0=
temp;
temp=
LOONGSON_GPIOIE0;
temp&= (~mask);
LOONGSON_GPIOIE0=
temp;
spin_unlock(&gpio_lock);
}
return0;
}
直到这里,gpio的调用过程已经完成了。
其余的函数:
ls2f_gpio_direction_input,
ls2f_gpio_get_value,
ls2f_gpio_direction_output,
ls2f_gpio_set_value,
的函数类似。
五、debugfs调试gpio端口
可以利用mount-t
debugfs none /mnt
那么可以在/mnt下面看到gpio文件
通过echo57
w1 > gpio
就可以对gpio的第57个关键写入1
疑问:为什么这样可以调试呢?
查看文件~/driver/gpio/gpiolib.c
staticconst
struct file_operations gpiolib_operations = {
.open =
gpiolib_open,
.read =
gpiolib_read,
.write
= gpiolib_write,
.llseek
= seq_lseek,
.release
= single_release,
};
staticint
__init gpiolib_debugfs_init(void)
{
(void)debugfs_create_file("gpio",
S_IFREG | S_IRUGO,
NULL,NULL,
&gpiolib_operations);
return0;
}
subsys_initcall(gpiolib_debugfs_init);
gpiolib_debugfs_init函数在内核启动的时候被调用。
于是创建了一个gpio文件,同时关联上了gpiolib_operations;
于是,echo57
w1 > gpio
相当于调用gpiolib_write函数;
staticssize_t
gpiolib_write(struct file *file, const char __user *buf,size_t
size, loff_t *ppos)
{
charinfo[255];
int
port=0,value=0;
memset(info,0,
255);
memcpy(info,buf,
size);
printk("gpio:%s\n",info);
if((info[0]>=
'0') && (info[0] <= '9')){
port=
(info[0] - 48)*10;
if((info[1]>=
'0') && (info[1] <= '9')){
port+=
(info[1] - 48);
if(info[2]==
' '){
if(info[3]
== 'w'){
value =
(info[4] == '0')?0:1;
}
}
}
}
if(info[3]==
'r'){
gpio_direction_input(port);
printk("gpio%dstatus
= %d\n", port, __gpio_get_value(port));
}elseif(info[3]
== 'w'){
printk("write%d
to gpio%d\n", value, port);
gpio_direction_output(port,
value);
__gpio_set_value(port,value);
}
returnsize;
}