1. platform_device 会包含platform_data 和 resource定义:
一般platform device信息,会定义在 arch/arm/mach-xxx/board-xxx.c 中。
如这里的sarac模块,被定义在arch/arm/mach-cartesio/core-sta2065.c中
static struct platform_device sarac_device = {
.name = "cartesio-sarac",
.id = 1,
.dev = {
.init_name = "cartesio-sarac",
//设备中包含的 platform数据
.platform_data = &sarac_platform_data,
},
.num_resources = ARRAY_SIZE(sarac_resource),
//包含的资源
.resource = sarac_resource,
};
这里的 .name 很重要,驱动会根据这个名字,在probe的时候进行匹配,如果有名字相同,就会匹配上。
platform_device 的定义如下:
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
};
他包含了一个设备dev,还有resource. 这些都是platform的优势,可以包含很多信息。
如上面的sarac_device,就包含了sarac_platform_data 和 sarac_resource 两块内容,具体定义如下:
static struct sarac_platform_data_container sarac_platform_data = {
//这个platform data 其实就是一个DMA slave 的定义
.mem2sarac_slave = {
.dma_dev = &dma0_device.dev, /* SARAC bound to DMA0 */
.tx_req_line = DMA0_REQ_SRC_DMA_DRE,
.rx_req_line = DMA0_REQ_SRC_DMA_DRF,
.nr_descs = 2048,
.channel = DMA_CHANNEL_AUTO,
.slave_width = DMA_TRANSFER_WIDTH_32BIT,
.flow_ctrlr = DMA_FLOW_CONTROLLER_DMA,
.burst_size = DMA_BURST_SIZE_1, /* fifo packet size */
.ahb_master = DMA_AHB_MASTER_0,
},
};
static struct resource sarac_resource[] = {
//resource 包含了两块,一块是寄存器访问地址, 一块是中断号信息
[0] = {
.start = CARTESIO_SARAC_BASE,
.end = CARTESIO_SARAC_BASE + SZ_4K - 1,
.name = "SaRaC registers",
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_SARAC_DRF,
.end = IRQ_SARAC_DRF,
.name = "CartesioPlus SaRaC interrupt",
.flags = IORESOURCE_IRQ,
},
};
2. 驱动probe中对platform的使用
模块加载时,会注册platform driver: 也就是 platform_driver_register()函数;
static int __init cartesio_sarac_init(void)
{
return platform_driver_register(&cartesio_sarac_driver);
}
module_init(cartesio_sarac_init);
cartesio_sarac_driver的定义如下:
static struct platform_driver cartesio_sarac_driver = {
.probe = cartesio_sarac_probe,
.remove = __devexit_p(cartesio_sarac_remove),
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
};
这里的.name 定义必须跟之前platform定义中的.name 一致,这样platform驱动和设备才能匹配上。
/*
* Asynchronous SaRaC device name
*/
#define DEVICE_NAME "cartesio-sarac"
该驱动被加载时,会自动运行cartesio_sarac_probe 函数:
static int __devinit cartesio_sarac_probe(struct platform_device *pdev)
{
struct sarac_device_data *sarac_device;
struct resource *res;
struct sarac_platform_data_container *sarac_plat_data=NULL;
int ret;
sarac_device = kzalloc(sizeof(struct sarac_device_data), GFP_KERNEL);
if (!sarac_device) {
dev_err(&pdev->dev, "not enough memory for driver status\n");
return -ENOMEM;
}
//通过这个函数,就把 platform_device 中的内容,赋给 sarac_device,就可以在这驱动中使用了
//这里的pdev 就是指向platform_device的指针。
platform_set_drvdata(pdev, sarac_device);
printk("SARAC probe called\n");
//该函数用来获取platform中的resource资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "register area not defined\n");
ret = -ENODEV;
goto out_free;
}
//把IO空间,赋值给sarac_device
sarac_device->base_addr = ioremap(res->start, resource_size(res));
if (!sarac_device->base_addr) {
dev_err(&pdev->dev, "unable to remap register area\n");
ret = -ENODEV;
goto out_free;
}
//把platform_device->dev.platform_data 赋值过来
sarac_plat_data = pdev->dev.platform_data;
if (sarac_plat_data->mem2sarac_slave.dma_dev) {
sarac_device->dma_to_sarac_client = &sarac_plat_data->mem2sarac_slave;
sarac_device->dma_to_sarac_client->tx_reg = res->start + SARAC_DILR;
sarac_device->dma_from_sarac_address = res->start + SARAC_DOLR;
} else {
dev_err(&pdev->dev, "DMA info not found in platform data\n");
ret = -1;
goto dma_err;
}
//把platform_device 中的IRQ 信息赋值过来
sarac_device->irq = platform_get_irq(pdev, 0);
//注册中断
ret = request_irq(sarac_device->irq, cartesio_sarac_irq_handler, 0,
dev_name(&pdev->dev), &pdev->id);
if (ret) {
dev_err(&pdev->dev, "failed to allocate IRQ %d\n", sarac_device->irq);
goto out_unmap;
}
else {
aab_peripheral_enable(AAB_SARAC, AAB_AC_WRITE | AAB_AC_READ);
}
//在sys中创建信息接口
sarac_kobj = kobject_create_and_add("audio_sarac", NULL);
if (!sarac_kobj)
return -ENOMEM;
ret = sysfs_create_group(sarac_kobj, &cartesio_sarac_attr_group);
if (ret)
return ret;
dev_info(&pdev->dev, "Module initialized, version" DRV_VERSION "\n");
return 0;
dma_err:
out_unmap:
iounmap(sarac_device->base_addr);
out_free:
kfree(sarac_device);
return ret;
}