linuxBSPmini2440之GPIO

 

linuxGPIO 的模型实现主要一个gpio-chip:(抽象一个GPIO控制器)

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;
 char   **names;
 unsigned  can_sleep:1;
 unsigned  exported:1;
};

---------------------------------------------------------------------------------------

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 
#define FLAG_TRIG_FALL 5 
#define FLAG_TRIG_RISE 6 

#define PDESC_ID_SHIFT 16 

#define GPIO_FLAGS_MASK  ((1 << PDESC_ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))

#ifdef CONFIG_DEBUG_FS
 const char  *label;
#endif
};

static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];定义了一个全局变量ARCH_NR_GPIOS是芯片GPIO口个数。

---------------------------------------------------------------------------------------

对于s3c2440来说,它有个GPIO-CORE.H,在这个文件夹中实现了对gpio-chip的封装和注册函数等。

---------------------------------------------------------------------------------

struct s3c_gpio_chip {
 struct gpio_chip chip;
 struct s3c_gpio_cfg *config;GPIO口设置结构体

 struct s3c_gpio_pm *pm;

 void __iomem  *base;//控制这个gpio组的首址寄存器
#ifdef CONFIG_PM
 u32   pm_save[4];存取寄存器控制器的值
#endif
};

-----------------------------------------------------------------------------------

下面先说看看这种模型是如何被加入系统中的,然后再看看在这个模型下,对外提供的API。

在plat-s3c24xx目录下的gpiolib.c中,我们看到了这么一个语句core_initcall(s3c24xx_gpiolib_init),

s3c24xx_gpiolib_init()函数就是在系统中注册GPIO的一个起始点。但是我们就会有疑问,这个函数是怎么被调用的,什么时候调用。这里就简单的说下,具体的以后分析。core_initcall().在linux\init.h中这么个定义

#define core_initcall(fn)  __define_initcall("1",fn,1)。

#define __define_initcall(level,fn,id) \
 static initcall_t __initcall_##fn##id __used \
 __attribute__((__section__(".initcall" level ".init"))) = fn

把core_initcall(s3c24xx_gpiolib_init)展开可以得到

—define_initcall("1",s3c24xx_gpiolib_init,1)--->

static initcall_t __initcall_ s3c24xx_gpiolib_init1 __used __attribute__((__section__(".initcall" 1 ".init")))=s3c24xx_gpiolib_init

__initcall_##fn##id ,这个是指针变量,所以整个意思就是把指向函数s3c24xx_gpiolib_init()的指针放入到.initcall1.init的输入段.系统中还有很多的其他输入端,那么这些段在哪里被调用呢。

start_kernel()-->rest_init()-->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND)-->

kernel_init()-->do_basic_setup()-->do_initcalls-->do_one_initcall-->ret.result = fn()

do_initcalls定义如下:

do_initcalls()

{

...

  for (call = __early_initcall_end; call < __initcall_end; call++)
  do_one_initcall(*call);

...

}

在__early_initcall_end和__initcall_end定义看arch/arm/kernel/vmlinux.lds

__initcall_start = .;
   *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;

所以属于.initcall1.init段的s3c24xx_gpiolib_init()函数会被调用。

关于core_initcall()就先到这。下面是接着叫GPIO

s3c24xx_gpiolib_init()定义如下:

----------------------------------------------------------------------------------

static __init int s3c24xx_gpiolib_init(void)
{
 struct s3c_gpio_chip *chip = s3c24xx_gpios;
 int gpn;

 for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++)
  s3c_gpiolib_add(chip);

 return 0;
}

-----------------------------------------------------------------------------------

在里面有个s3c24xx_gpios中的没一个元素被s3c_gpiolib_add()调用一次。在本文件内我们还看到

-----------------------------------------------------------------------------------------

struct s3c_gpio_chip s3c24xx_gpios[] = {
 [0] = {
  .base = S3C2410_GPACON,
  .pm = __gpio_pm(&s3c_gpio_pm_1bit),
  .chip = {
   .base   = S3C2410_GPA(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOA",
   .ngpio   = 24,
   .direction_input = s3c24xx_gpiolib_banka_input,
   .direction_output = s3c24xx_gpiolib_banka_output,
  },
 },
 [1] = {
  .base = S3C2410_GPBCON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPB(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOB",
   .ngpio   = 16,
  },
 },
 [2] = {
  .base = S3C2410_GPCCON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPC(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOC",
   .ngpio   = 16,
  },
 },
 [3] = {
  .base = S3C2410_GPDCON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPD(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOD",
   .ngpio   = 16,
  },
 },
 [4] = {
  .base = S3C2410_GPECON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPE(0),
   .label   = "GPIOE",
   .owner   = THIS_MODULE,
   .ngpio   = 16,
  },
 },
 [5] = {
  .base = S3C2410_GPFCON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPF(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOF",
   .ngpio   = 8,
   .to_irq   = s3c24xx_gpiolib_bankf_toirq,
  },
 },
 [6] = {
  .base = S3C2410_GPGCON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPG(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOG",
   .ngpio   = 16,
   .to_irq   = s3c24xx_gpiolib_bankg_toirq,
  },
 }, {
  .base = S3C2410_GPHCON,
  .pm = __gpio_pm(&s3c_gpio_pm_2bit),
  .chip = {
   .base   = S3C2410_GPH(0),
   .owner   = THIS_MODULE,
   .label   = "GPIOH",
   .ngpio   = 11,
  },
 },
};

---------------------------------------------------------------------------------------------

s3c24xx_gpios有七个元素。每一个元素与GPIO口的A,B,C,D,E,F,H组一一对应。拿第一个元素来说就对应A组GPIO。它描述了这组口的一些性质。外面.base是GPACON寄存器的首地址,里面.chip结构体的.base代表该组的第一个引脚。因为A口没有输入功能所以s3c24xx_gpiolib_banka_input为空。s3c24xx_gpiolib_banka_output()设置某个引脚输出的电平值。offset是第几位,value是电平值。第5,6组因为可以设置中断引脚所以.to_irq被赋值。

linuxBSPmini2440之GPIO
linuxBSPmini2440之GPIO
s3c24xx_gpiolib_bankf_toirq
s3c24xx_gpiolib_bankg_toirq是怎么设置中断呢。
---------------------------------------------------------------------------------
static int s3c24xx_gpiolib_bankf_toirq(struct gpio_chip *chip, unsigned offset)
{
  if (offset < 4)
    return IRQ_EINT0 + offset;
 
  if (offset < 8)
    return IRQ_EINT4 + offset - 4;
 
  return -EINVAL;
}

-------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------

static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset)
{
 return IRQ_EINT8 + offset;
}

-------------------------------------------------------------------------------------------

为什么这样编写呢。这就关心到中断号了。有主中断和次中断。


#define IRQ_EINT0      S3C2410_IRQ(0)    
#define IRQ_EINT1      S3C2410_IRQ(1)
#define IRQ_EINT2      S3C2410_IRQ(2)
#define IRQ_EINT3      S3C2410_IRQ(3)
#define IRQ_EINT4t7    S3C2410_IRQ(4)    
#define IRQ_EINT8t23   S3C2410_IRQ(5)
#define IRQ_RESERVED6  S3C2410_IRQ(6)    
#define IRQ_CAM        S3C2410_IRQ(6)    
#define IRQ_BATT_FLT   S3C2410_IRQ(7)
#define IRQ_TICK       S3C2410_IRQ(8)    
#define IRQ_WDT        S3C2410_IRQ(9)    
#define IRQ_TIMER0     S3C2410_IRQ(10)
#define IRQ_TIMER1     S3C2410_IRQ(11)
#define IRQ_TIMER2     S3C2410_IRQ(12)
#define IRQ_TIMER3     S3C2410_IRQ(13)
#define IRQ_TIMER4     S3C2410_IRQ(14)
#define IRQ_UART2      S3C2410_IRQ(15)
#define IRQ_LCD        S3C2410_IRQ(16)    
#define IRQ_DMA0       S3C2410_IRQ(17)    
#define IRQ_DMA1       S3C2410_IRQ(18)
#define IRQ_DMA2       S3C2410_IRQ(19)
#define IRQ_DMA3       S3C2410_IRQ(20)
#define IRQ_SDI        S3C2410_IRQ(21)
#define IRQ_SPI0       S3C2410_IRQ(22)
#define IRQ_UART1      S3C2410_IRQ(23)
#define IRQ_RESERVED24 S3C2410_IRQ(24)    
#define IRQ_NFCON      S3C2410_IRQ(24)    
#define IRQ_USBD       S3C2410_IRQ(25)
#define IRQ_USBH       S3C2410_IRQ(26)
#define IRQ_IIC        S3C2410_IRQ(27)
#define IRQ_UART0      S3C2410_IRQ(28)    
#define IRQ_SPI1       S3C2410_IRQ(29)
#define IRQ_RTC        S3C2410_IRQ(30)
#define IRQ_ADCPARENT  S3C2410_IRQ(31)


#define IRQ_EINT4      S3C2410_IRQ(32)   
#define IRQ_EINT5      S3C2410_IRQ(33)
#define IRQ_EINT6      S3C2410_IRQ(34)
#define IRQ_EINT7      S3C2410_IRQ(35)
#define IRQ_EINT8      S3C2410_IRQ(36)
#define IRQ_EINT9      S3C2410_IRQ(37)
#define IRQ_EINT10     S3C2410_IRQ(38)
#define IRQ_EINT11     S3C2410_IRQ(39)
#define IRQ_EINT12     S3C2410_IRQ(40)
#define IRQ_EINT13     S3C2410_IRQ(41)
#define IRQ_EINT14     S3C2410_IRQ(42)
#define IRQ_EINT15     S3C2410_IRQ(43)
#define IRQ_EINT16     S3C2410_IRQ(44)
#define IRQ_EINT17     S3C2410_IRQ(45)
#define IRQ_EINT18     S3C2410_IRQ(46)
#define IRQ_EINT19     S3C2410_IRQ(47)
#define IRQ_EINT20     S3C2410_IRQ(48)   
#define IRQ_EINT21     S3C2410_IRQ(49)
#define IRQ_EINT22     S3C2410_IRQ(50)
#define IRQ_EINT23     S3C2410_IRQ(51)

.ngpio的该组多少个引脚。.label只是对该组的一个标记符。其他的初始化在后面。.pm可以通过如下知道他的值。

如果定义了PM,那么__gpio_pm(x)就为x。

#ifdef CONFIG_PM
extern struct s3c_gpio_pm s3c_gpio_pm_1bit;
extern struct s3c_gpio_pm s3c_gpio_pm_2bit;
extern struct s3c_gpio_pm s3c_gpio_pm_4bit;
#define __gpio_pm(x) x
#else
#define s3c_gpio_pm_1bit NULL
#define s3c_gpio_pm_2bit NULL
#define s3c_gpio_pm_4bit NULL
#define __gpio_pm(x) NULL

#endif

那么这样的7个元素怎么加入的呢。看s3c_gpiolib_add()

-----------------------------------------------------------------------------------------------

__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
 struct gpio_chip *gc = &chip->chip;
 int ret;

 BUG_ON(!chip->base);
 BUG_ON(!gc->label);
 BUG_ON(!gc->ngpio);

 if (!gc->direction_input)
  gc->direction_input = s3c_gpiolib_input;
 if (!gc->direction_output)
  gc->direction_output = s3c_gpiolib_output;
 if (!gc->set)
  gc->set = s3c_gpiolib_set;
 if (!gc->get)
  gc->get = s3c_gpiolib_get;

#ifdef CONFIG_PM
 if (chip->pm != NULL) {
  if (!chip->pm->save || !chip->pm->resume)
   printk(KERN_ERR "gpio: %s has missing PM functions\n",
          gc->label);
 } else
  printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
#endif

 
 ret = gpiochip_add(gc);
 if (ret >= 0)
  s3c_gpiolib_track(chip);
}
-------------------------------------------------------------------------------------------------

#define BUG_ON(a) if((a)) printf("bug report at line %d from  %s\n",__LINE__,__FUNCTION__)

 BUG_ON(!chip->base);
 BUG_ON(!gc->label);
 BUG_ON(!gc->ngpio);

所以,这里不难看懂了吧。然后进行相关chip的初始化。PM中save和resume分别是保存控制器的值和恢复控制器的值。它的值保存在pm_save[4]里。

gpiochip_add(gc)做什么,这里是真正的注册GPIO了。看源代码:

-----------------------------------------------------------------------------------------

int gpiochip_add(struct gpio_chip *chip)
{
 unsigned long flags;
 int  status = 0;
 unsigned id;
 int  base = chip->base;

 if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
   && base >= 0) {
  status = -EINVAL;
  goto fail;
 }

 spin_lock_irqsave(&gpio_lock, flags);

 if (base < 0) {
  base = gpiochip_find_base(chip->ngpio);
  if (base < 0) {
   status = base;
   goto unlock;
  }
  chip->base = base;
 }

 
 for (id = base; id < base + chip->ngpio; id++) {
  if (gpio_desc[id].chip != NULL) {
   status = -EBUSY;
   break;
  }
 }
 if (status == 0) {
  for (id = base; id < base + chip->ngpio; id++) {
   gpio_desc[id].chip = chip;

   
   gpio_desc[id].flags = !chip->direction_input
    ? (1 << FLAG_IS_OUT)
    : 0;
  }
 }

unlock:
 spin_unlock_irqrestore(&gpio_lock, flags);
 if (status == 0)
  status = gpiochip_export(chip);
fail:
 
 if (status)
  pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
   chip->base, chip->base + chip->ngpio - 1,
   chip->label ? : "generic");
 return status;
}

-----------------------------------------------------------------------------------------

这里通过base值和.ngpio来确定gpio_desc[],为这个全局变量赋值。如果gpio_desc[]已经注册过了就会退出。

在这里我们就可以知道。gpio_desc[]记录了每一个gpio的属性。注意这里面的一个元素就是一个GPIO引脚。而这个元素是gpio_desc类型,它包含一个指向gpio_chip的结构体,这个结构体是这个引脚所属的GPIO组(A,或者B...)。

到这里,我其实有个疑问,在另外的一个mach-s3c2440中clock.c文件中有实现GPIO控制的API,这里又有,为什么弄这么多呢?

你可能感兴趣的:(c,timer,struct,Module,input,output)