Chinaunix首页 | 论坛 | 博客
  • 博客访问: 362929
  • 博文数量: 135
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 599
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-19 21:10
文章分类
文章存档

2014年(3)

2013年(79)

2012年(53)

分类: LINUX

2013-10-23 14:33:33

原文地址:platform_get_resource 作者:守候心田

阅读aml_i2c的代码时,发现在probe函数直接调用了platform_get_resource获取io内存,但是却没有做任何检测!probe函数怎么知道这块io内存属于这个驱动呢?

后来发现原来在arch目录下的对应目录里面有个board-8726m-refa00.c文件,这个文件里面声明了一个platform设备的资源数组platform_devs,原型如下:

static struct platform_device __initdata *platform_devs[]= {
    #if defined(CONFIG_TOUCHSCREEN_ADS7846)
  &spi_gpio,
    #endif
 
    #if defined(CONFIG_AML_RTC)
  &aml_rtc_device,
    #endif
 #if defined(CONFIG_SUSPEND)
  &aml_pm_device,
    #endif

    ...

    #if defined(CONFIG_I2C_AML)
  &aml_i2c_device,
    #endif

    ...
}


这个数组里面包含了所有platform设备的资源信息。例如:aml_i2c设备的资源声明如下:

#if defined(CONFIG_I2C_AML)
static struct aml_i2c_platform aml_i2c_plat = {
 .wait_count  = 1000000,
 .wait_ack_interval = 5,
 .wait_read_interval = 5,
 .wait_xfer_interval = 5,
 .master_no  = AML_I2C_MASTER_B,
 .use_pio   = 0,
 .master_i2c_speed = AML_I2C_SPPED_400K,

 .master_b_pinmux = {
  .scl_reg = MESON_I2C_MASTER_B_GPIOB_0_REG,
  .scl_bit = MESON_I2C_MASTER_B_GPIOB_0_BIT,
  .sda_reg = MESON_I2C_MASTER_B_GPIOB_1_REG,
  .sda_bit = MESON_I2C_MASTER_B_GPIOB_1_BIT,
 }
};

static struct resource aml_i2c_resource[] = {
 [0] = {/*master a*/
  .start =  MESON_I2C_MASTER_A_START,
  .end   =  MESON_I2C_MASTER_A_END,
  .flags =  IORESOURCE_MEM,
 },
 [1] = {/*master b*/
  .start =  MESON_I2C_MASTER_B_START,
  .end   =  MESON_I2C_MASTER_B_END,
  .flags =  IORESOURCE_MEM,
 },
 [2] = {/*slave*/
  .start =  MESON_I2C_SLAVE_START,
  .end   =  MESON_I2C_SLAVE_END,
  .flags =  IORESOURCE_MEM,
 },
};

static struct platform_device aml_i2c_device = {
 .name    = "aml-i2c",
 .id    = -1,
 .num_resources   = ARRAY_SIZE(aml_i2c_resource),
 .resource   = aml_i2c_resource,
 .dev = {
  .platform_data = &aml_i2c_plat,
 },
};
#endif


那么将这个aml_i2c_device加入platform_devs[] 数组,就能直接在probe函数中用platform_get_resource获取资源了,但是要注意驱动的名称必须和platform_device结构中的名称完全相同。

那为什么加入platform_devs数组后就能直接访问了呢?
在相关体系的machine_desc结构体中(对于每个特定平台都有一 个MACHINE_START宏用来定义machine_desc结构体),有一个接口init_machine,这个接口中会调用 platform_add_devices添加platform_devs。例如:

platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));

 

其中platform_device的资源,资源本身由 resource结构体描述,其定义如下:

resouce结构体定义

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

我们通常关心start、end和flags这3个字段,分别标明资源的开始值、结束值和类型,flags可以为IORESOURCE_IO、 IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA等。
start、end的含义会随着flags而变更,如当flags为IORESOURCE_MEM时,start、end分别表示该platform_device占据的内存的开始地址和结束地址;
当flags为IORESOURCE_IRQ时,start、end分别表示该platform_device使用的中断号的开始值和结束值,如果只使用了1个中断号,开始和结束值相同。
对于同种类型的资源而言,可以有多份,譬如说某设备占据了2个内存区域,则可以定义2个IORESOURCE_MEM资源。
resource的定义也通常在BSP的板文件中进行,而在具体的设备驱动中透过platform_get_resource()这样的API来获取,此API的原型为:

struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);


在aml_i2c的驱动中则是通过如下办法拿到这2份资源:

aml-i2c.c文件中aml_i2c_probe()函数中
i2c->master_no = plat->master_no;   /*master a:0 master b:1*/

/*master a or master b*/
res = platform_get_resource(pdev, IORESOURCE_MEM, i2c->master_no);   //通过下面可知master_no 为1,即master b

等价于下面两句:

xxx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);   //master a
yyy_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);   //master b


对于IRQ而言,platform_get_resource()还有一个进行了封装的变体platform_get_irq(),其原型为:
int platform_get_irq(struct platform_device *dev, unsigned int num);
它实际上调用了“platform_get_resource(dev, IORESOURCE_IRQ, num);”。

设备除了可以在BSP中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断、内存、DMA通道以外,可能还会有一些配置信息,
而这些配置信息也依赖于板,不适宜直接放置在设备驱动本身,因此,platform也提供了platform_data的支持。platform_data 的形式是自定义的,
如对于aml-i2c而言,platform_data为一个aml_i2c_plat结构体,我们就可以将使用master a还是master b,i2c speed等信息放入platform_data:

static struct aml_i2c_platform aml_i2c_plat = {
 .wait_count  = 1000000,     // i2c wait ack timeout
 .wait_ack_interval = 5,
 .wait_read_interval = 5,
 .wait_xfer_interval = 5,
 .master_no  = AML_I2C_MASTER_B,    //AML_I2C_MASTER_B值为1  即master b
 .use_pio   = 0,           //0: hardware i2c, 1: manual pio i2c
 .master_i2c_speed = AML_I2C_SPPED_400K,  //AML_I2C_SLAVE_ADDR=0x6c

 .master_b_pinmux = {
  .scl_reg = MESON_I2C_MASTER_B_GPIOB_0_REG,
  .scl_bit = MESON_I2C_MASTER_B_GPIOB_0_BIT,
  .sda_reg = MESON_I2C_MASTER_B_GPIOB_1_REG,
  .sda_bit = MESON_I2C_MASTER_B_GPIOB_1_BIT,
 }
};

static struct platform_device aml_i2c_device = {
 .name    = "aml-i2c",
 .id    = -1,
 .num_resources   = ARRAY_SIZE(aml_i2c_resource),
 .resource   = aml_i2c_resource,
 .dev = {
  .platform_data = &aml_i2c_plat,
 },
};

而在aml-i2c的驱动中,通过如下方式就拿到了platform_data:
struct aml_i2c_platform *plat = pdev->dev.platform_data;
其中,pdev为platform_device的指针。

另,在platform_device中的 .resource 也可以不定义而放在 .platform_data中自定义 .resource

阅读(1824) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~