linux platform_get_resource,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 。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值