概念
-
一种虚拟总线,由内核创建
-
一般在内核代码中已近注册了相应的平台资源,在sys/bus/platform中可以查看平台的设备和驱动
平台设备:(查看内核document/driver-model目录下的文档)
-
平台设备是一种典型的自动挂载进系统的设备
-
它包含有设备的端口基地址和设备外设总线
-
很多控制器为完善系统的集成度,在上电时自动引导平台设备到内核中去,平台设备中的资源对应的基地址是直接的物理地址,但是驱动设备获取平台资源要使用平台资源获取函数来获取对应的地址信息。
平台设备驱动开发分为两个步骤
处理平台设备
-
定义平台设备
-
注册平台设备
-
注销平台设备
处理平台驱动
-
定义平台驱动
-
注册平台驱动
-
注销平台驱动
平台设备驱动模型的匹配机制
a) 与总线设备驱动模型的匹配机制是同一个原理
b) 总线通过其设备名和驱动名的匹配(或者是产品的ID号进行匹配)
平台设备描述结构
struct platform_device {
const char* name;/*平台设备名,必须和匹配的驱动名同名*/
int id; /*设备编号,配合设备名使用*/
struct devicedev;/*总线设备,平台驱动需要调用释放函数*/
u32num_resources;/*资源数量.,看资源的种类*/
struct resource* resource;/*设备资源*/
const struct platform_device_id *id_entry;
struct mfd_cell *mfd_cell; /* MFD cell pointer */
struct pdev_archdata archdata; /* arch specific additions */
};
驱动比较关心的是该结构体的名字和资源;对于设备资源,对应的结构体描述为
struct resource {
resource_size_t start;/*资源的起始地址*/
resource_size_t end;/*资源的结束地址*/
const char *name; /*资源名称*/
unsigned long flags;/*标识资源的类型*/
struct resource *parent, *sibling, *child; /*资源链表,内核自行处理*/
};
使用资源的好处是:
-
表示某个实体的一部分,这部分被互斥地分配给设备驱动程序
-
一个资源表示I/O端口地址的一个范围
-
每个资源对应的信息存放在resource数据结构中
-
资源类型可以是 I/O内存、中断号、DMA等
平台设备相关函数
1.平台设备注册
int platform_device_register(struct platform_device *);
2.平台设备注销
void platform_device_unregister(struct platform_device *);
3.平台资源获取
struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
流程:定义平台设备->注册平台设备->注销平台设备
平台驱动描述结构
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;/*需要初始化其中的name成员来匹配平台设备*/
const struct platform_device_id *id_table;
};
使用规范:
-
由于平台设备已经初始化了相应的平台资源,既硬件资源,所以在该驱动使用 时,使用平台资源获取函数,然后再进行io映射初始化即可
-
注意平台结构中driver.name需要和平台设备匹配
-
初始化一般放在设备捕获函数中进行
-
资源的释放对应在remove对应的函数中
-
模块入口函数只需要进行平台驱动的 注册/注销 就行了
注册函数:
int platform_driver_register(struct platform_driver *);
注销函数:
platform_driver_unregister(struct platform_driver *);
驱动程序设计
平台设备
/************************************
作者:hntea
时间:2016/3/16
函数功能:平台总线测试
************************************/
#include<linux/init.h>
#include<linux/module.h>
#include<linux/device.h>
#include<linux/platform_device.h>
#include<linux/interrupt.h>
#include<linux/fs.h>
#include<linux/miscdevice.h>
#include<linux/mm.h>
#include<linux/io.h>
/***********************************
函数名:
函数功能:混杂设备初始化
函数参数
***********************************/
int key_open (struct inode *inode, struct file *filep)
{
return 0;
}
struct file_operations key_fops =
{
.open = key_open,
};
struct miscdevice key_miscdev =
{
.name = "keydevices",
.minor = 10,
.fops = &key_fops,
};
/***********************************
函数名:
函数功能:中断处理
函数参数
***********************************/
static irqreturn_t key1_hander (int irq, void *dev_id)
{
printk("key1 down!\n");
return 0;
}
static irqreturn_t key2_hander (int irq, void *dev_id)
{
printk("key2 down!\n");
return 0;
}
static irqreturn_t key3_hander (int irq, void *dev_id)
{
printk("key3 down!\n");
return 0;
}
static irqreturn_t key4_hander (int irq, void *dev_id)
{
printk("key4 down!\n");
return 0;
}
/***********************************
函数名:
函数功能:定义平台驱动
函数参数:
***********************************/
struct resource* res_irq;
struct resource* res_iomem;
unsigned int* key_ioconfig;
int key_probe(struct platform_device *pdev)
{
int ret = 0;
int size = 0;
unsigned int temdata=0;
printk("Probe Devices Success!\n");
/*初始化事就交到这里*/
/*注册混杂设备*/
ret = misc_register(&key_miscdev);
/*注册中断*/
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
ret = request_irq(res_irq->start + 0,key1_hander,IRQF_TRIGGER_FALLING,"key1",0);
ret = request_irq(res_irq->start + 1,key2_hander,IRQF_TRIGGER_FALLING,"key2",0);
ret = request_irq(res_irq->start + 2,key3_hander,IRQF_TRIGGER_FALLING,"key3",0);
ret = request_irq(res_irq->start + 3,key4_hander,IRQF_TRIGGER_FALLING,"key4",0);
/*硬件初始化*/
res_iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); /*最后一个参数是索引*/
size = (res_iomem->end - res_iomem->start); /*8个字节*/
key_ioconfig = ioremap(res_iomem->start,size);
temdata = ioread32(key_ioconfig);
temdata &= (~0xfffff);
temdata |= 0xfffff;
iowrite32(temdata,key_ioconfig);
return ret;
}
int key_remove(struct platform_device *pdev)
{
/*注销设备*/
misc_deregister(&key_miscdev);
/*释放中断*/
free_irq(res_irq->start + 0, 0);
free_irq(res_irq->start + 1, 0);
free_irq(res_irq->start + 2, 0);
free_irq(res_irq->start + 3, 0);
/*注销内存*/
iounmap(key_ioconfig);
return 0;
}
/*平台驱动成员初始化*/
static struct platform_driver key_driver = {
.probe = key_probe,
.remove = key_remove,
.driver = {
.owner = THIS_MODULE,
.name = "keydevices",
},
};
/***********************************
函数名:
函数功能:
函数参数
***********************************/
static int keyPlatformDriverInit(void)
{
int ret = 0;
/*平台驱动注册*/
if( (ret = platform_driver_register(&key_driver))<0)
{
printk("platform_driver_register err!\n");
}
return ret;
}
static void keyPlatformDriverExit(void)
{
/*平台驱动注销*/
platform_driver_unregister(&key_driver);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hntea");
module_init(keyPlatformDriverInit);
module_exit(keyPlatformDriverExit);
平台设备
/************************************
作者:hntea
时间:2016/3/16
函数功能:平台总线测试
************************************/
#include<linux/init.h>
#include<linux/module.h>
#include<linux/device.h>
#include<linux/platform_device.h>
#include<linux/interrupt.h>
#define KEY_GPH0CON 0xE0200C00
/*定义平台资源*/
void key_release(struct device *dev)
{
printk("key source release!\n");
}
struct resource key_resource [] = {
/*IO端口资源*/
[0] = {
.start = KEY_GPH0CON,
.end = KEY_GPH0CON + 8, /*配置寄存器加上数据寄存器,每个寄存器四个字节*/
.flags = IORESOURCE_MEM, },
/*外部中断资源*/
[1] ={
.start = IRQ_EINT0,
.end = IRQ_EINT5,
.flags = IORESOURCE_IRQ,},
};
/*定义平台设备*/
struct platform_device key_devices = {
.name = "keydevices",
.id = 0,
.num_resources = ARRAY_SIZE(key_resource), /*用宏来求资源类型的数量*/
.resource = key_resource,
.dev = {
.release = key_release,},
};
/*设备注册*/
static int keyPlatformDeviceInit(void)
{
int ret = 0;
ret = platform_device_register(&key_devices);
return ret;
}
/*设备卸载*/
static void keyPlatformDeviceExit(void)
{
platform_device_unregister(&key_devices);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hntea");
module_init(keyPlatformDeviceInit);
module_exit(keyPlatformDeviceExit);