Linux内核platform_get_resource函数如何得到设备的基地址

以I2c-s3c2410.c驱动为例:

……

 /* map the registers */

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 if (res == NULL) {
  dev_err(&pdev->dev, "cannot find IO resource\n");
  ret = -ENOENT;
  goto err_clk;
 }

 i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
      pdev->name);

 if (i2c->ioarea == NULL) {
  dev_err(&pdev->dev, "cannot request IO\n");
  ret = -ENXIO;
  goto err_clk;
 }

 i2c->regs = ioremap(res->start, (res->end-res->start)+1);

……

最终得到了IIC的基地址:i2c->regs

以后只需要在基地址的基础上加上偏移量即可得到相应的寄存器,偏移量和寄存器操作宏 定义在regs-iic.h中:

寄存器:

#define S3C2410_IICREG(x) (x)

#define S3C2410_IICCON    S3C2410_IICREG(0x00)
#define S3C2410_IICSTAT   S3C2410_IICREG(0x04)
#define S3C2410_IICADD    S3C2410_IICREG(0x08)
#define S3C2410_IICDS     S3C2410_IICREG(0x0C)
#define S3C2440_IICLC   S3C2410_IICREG(0x10)

操作宏:

#define S3C2410_IICCON_ACKEN  (1<<7)
#define S3C2410_IICCON_TXDIV_16  (0<<6)
#define S3C2410_IICCON_TXDIV_512 (1<<6)
#define S3C2410_IICCON_IRQEN  (1<<5)
#define S3C2410_IICCON_IRQPEND  (1<<4)
#define S3C2410_IICCON_SCALE(x)  ((x)&15)
#define S3C2410_IICCON_SCALEMASK (0xf)

……

现在遇到的问题是:为什么通过platform_get_resource、ioremap等一系列函数就能得到I2C寄存器的基地址呢?

解答:

 因为通过platform_get_resource,返回一个resource结构指针,我们来看一下这个结构指针:

struct resource {
 resource_size_t start;
 resource_size_t end;
 const char *name;
 unsigned long flags;
 struct resource *parent, *sibling, *child;
};

再来看一下arch\arm\plat-s3c24xx目录下的devs.c文件是如何定义I2C资源的:

static struct resource s3c_i2c_resource[] = {
 [0] = {
  .start = S3C24XX_PA_IIC,
  .end   = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,
  .flags = IORESOURCE_MEM,
 },
 [1] = {
  .start = IRQ_IIC,
  .end   = IRQ_IIC,
  .flags = IORESOURCE_IRQ,
 }

};

其中,S3C24XX_PA_IIC就是S3C24XX系列芯片的I2c基地址,它的定义在arch\arm\mach-s3c2410\include\mach目录下的map.h文件中,具体如下

……

#define S3C2410_PA_IIC    (0x54000000)

……

#define S3C24XX_PA_IIC      S3C2410_PA_IIC

……

基地址为0x54000000,这样就与芯片手册对应了起来。

 

 

你可能感兴趣的:(片内驱动开发(I2C,NAND,Flash,LINUX内核))