GPIO驱动相关笔记

 

打算跟着友善之臂的《mini2440 linux移植开发指南》来做个LED驱动,虽然LED的原理简单得不能再简单了,但是要把kernel中针对于s3c24**的GPIO的一些数据结构,还有函数搞清楚也不是那么轻松的事,所以本文主要简单地说明下LED驱动中的相关数据结构以及函数/宏的定义,并对驱动加以验证

 

*************************************************************************** 

注意:在/arch/arm/mach-s3c2410/include/mach/gpio-fns.h源代码中有如下说明:

 16/* These functions are in the to-be-removed category and it is strongly
17 * encouraged not to use these in new code. They will be marked deprecated
18 * very soon.
19 *
20 * Most of the functionality can be either replaced by the gpiocfg calls
21 * for the s3c platform or by the generic GPIOlib API.
22 *
23 * As of 2.6.35-rc, these will be removed, with the few drivers using them
24 * either replaced or given a wrapper until the calls can be removed.
25*/

 

该头文件包括:

static inline void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int cfg)

该函数直接使用

linux/arch/arm/plat-s3c/gpio-config.c中的

int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)

即可 

 

*************************************************************************** 

 

首先看一下设备初始化程序:

85 /*
86 * 设备初始化
87 */

88 static int __init dev_init(void)
89 {
90 int ret;
91 int i;
92 for (i = 0; i < 4; i++) {
93 //设置 LED 对应的端口寄存器为输出(OUTPUT)
94        
if (s3c_gpio_cfgpin(led_table[i], led_cfg_table[i])<0)

                       printk(KERN_INFO "config pin %d failed", i);


95 printk(KERN_INFO "config pin %d failed", i);

95 //设置 LED 对应的端口寄存器为低电平输出,在模块加载> 结束后,四个 LED 应该是全部都是发光
96 状态
 97         s3c2410_gpio_setpin(led_table[i], 0);
98 }
 99  ret = misc_register(&misc); //注册设备
100 printk (DEVICE_NAME"/tinitialized/n"); //打印初始化信息
101 return ret;
102 }

 

可以看到,这里涉及到两个函数,分别是s3c2410_gpio_cfgpin,s3c2410_gpio_setpin,这两个函数分别对四个LED进行配置,从函数名来看,cfgpin对引脚寄存器状态进行配置,而setpin应该是对寄存器数据值进行配置,我们在分析函数之前先弄清楚传入的参数到底是什么。

led_table[i]
28 //LED 对应的 GPIO 端口列表
29 static unsigned long led_table [] = {
 30     S3C2410_GPB(5),
 31     S3C2410_GPB(6),
 32     S3C2410_GPB(7),
 33     S3C2410_GPB(8),
34 };

这里S3C2410_GPB宏定义在mach/gpio-nrs.h中 
/* GPIO bank sizes */
#define S3C2410_GPIO_A_NR (32)
#define S3C2410_GPIO_B_NR (32)
#define S3C2410_GPIO_C_NR (32)
#define S3C2410_GPIO_D_NR (32)
#define S3C2410_GPIO_E_NR (32)
#define S3C2410_GPIO_F_NR (32)
#define S3C2410_GPIO_G_NR (32)
#define S3C2410_GPIO_H_NR (32)
#define S3C2410_GPIO_J_NR (32) /* technically 16. */
#define S3C2410_GPIO_K_NR (32) /* technically 16. */
#define S3C2410_GPIO_L_NR (32) /* technically 15. */
#define S3C2410_GPIO_M_NR (32) /* technically 2. */

 

#if CONFIG_S3C_GPIO_SPACE != 0
#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment
#endif
 

 

#define S3C2410_GPIO_NEXT(__gpio) /
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)

 

//这里的CONFIG_S3C_GPIO_SPAC是内核配置选项,在.config中可以找到,我的配置为:

CONFIG_S3C_GPIO_SPACE = 0 

 

enum s3c_gpio_number {
S3C2410_GPIO_A_START = 0,
S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
};

#define S3C2410_GPB(_nr)    (S3C2410_GPIO_B_START + (_nr))  

因此,以S3C2410_GPB(5)为例,其宏展开为:

S3C2410_GPIO_NEXT(S3C2410_GPIO_A) +5 => 

(S3C2410_GPIO_A_START + S3C2410_GPIO_A_NR +  CONFIG_S3C_GPIO_SPACE + 0) + 5 =>

很显然, S3C2410_GPB(5)就是从GPA的首地址+GPA个数+GPB的offset就是当前GPB的IO偏移量,即

0+32+5=37, 同理

          S3C2410_GPB(0) 相当于 32

 30     S3C2410_GPB(5) 相当于 37
 31     S3C2410_GPB(6) 相当于 38
 32     S3C2410_GPB(7) 相当于 39
 33     S3C2410_GPB(8) 相当于 40

*************************************************************************** 

 led_cfg_table[i]

36 //LED 对应端口将要输出的状态列表
37 static unsigned int led_cfg_table [] = {
38 S3C2410_GPIO_OUTPUT,
39 S3C2410_GPIO_OUTPUT,
40 S3C2410_GPIO_OUTPUT,
41 S3C2410_GPIO_OUTPUT,
42 };

S3C2410_GPIO_OUTPUT定义在mach/regs-gpio.h

#define S3C2410_GPIO_LEAVE (0xFFFFFFFF)                                             // 最后两位是设置,11表示RESERVE
#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */        
// 最后两位是设置,00表示INPUT

#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)                                         // 最后两位是设置,01表示OUTPUT
#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */
#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */
#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */

*************************************************************************** 

根据前面的分析,s3c2410传入了当前GPIO的偏移地址,以及OUTPUT状态

现在我们深入前面的两个函数:

定义在linux/arch/arm/plat-s3c/gpio-config.c
int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
{
struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);   //得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数
unsigned long flags;
int offset;
int ret;

if (!chip)
     return -EINVAL;   // 没找到的话,返回invalid

 offset = pin - chip->chip.base;    // 否则offset等于该GPIO引脚相对于GPX(0)的偏移量,每个偏移1

s3c_gpio_lock(chip, flags);    // 自旋锁锁住该GPIO,通过chip指针指向lock,看下面的define和图
ret = s3c_gpio_do_setcfg(chip, offset, config);    //设置该GPIO状态寄存器的数值为config
s3c_gpio_unlock(chip, flags);  // 解锁

 

// 自旋锁操作
/* locking wrappers to deal with multiple access to the same gpio bank */
//#define s3c_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl)

//#define

你可能感兴趣的:(struct,c,数据结构,module,output,class)