linux多个驱动对应一板卡,Linux 下的GPIO驱动

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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值