linux platform平台设备驱动

一. 平台总线

    1. 总线结构体

struct bus_type platform_bus_type = {
	.name		= "platform",		//总线名
	.dev_attrs	= platform_dev_attrs,	//设备属性
	.match		= platform_match,		//匹配函数
	.uevent		= platform_uevent,		//事件函数
	.pm		= &platform_dev_pm_ops,	//电源管理函数集
};

 

    2.总线的初始化

int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);	//注册平台总线设备
	if (error)
		return error;
	error =  bus_register(&platform_bus_type);	//注册平台总线
	if (error)
		device_unregister(&platform_bus);
	return error;
}

 

    3.paltform_match方法

static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);	//根据设备文件获取对应的平台设备
	struct platform_driver *pdrv = to_platform_driver(drv);	//根据驱动文件获取对应的平台驱动

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))		//类型匹配?
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)				//id表匹配?
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);		//名字匹配
}

 

二. 平台设备

   1.平台设备结构体

struct platform_device {
	const char	* name;	//设备名
	int		id;	//设备id
	struct device	dev;	//设备文件
	u32		num_resources;	//设备资源数
	struct resource	* resource;	//设备资源

	const struct platform_device_id	*id_entry;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

    2.平台设备注册

int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	return platform_device_add(pdev);
}

    2.1 平台添加设备

int platform_device_add(struct platform_device *pdev)
{
	int i, ret = 0;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;	//设置父设备

	pdev->dev.bus = &platform_bus_type;		//设置设备总线类型

	if (pdev->id != -1)			//设置设备文件名
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
	else
		dev_set_name(&pdev->dev, "%s", pdev->name);

	for (i = 0; i < pdev->num_resources; i++) {	//设置资源文件
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);

		p = r->parent;
		if (!p) {
			if (resource_type(r) == IORESOURCE_MEM)
				p = &iomem_resource;
			else if (resource_type(r) == IORESOURCE_IO)
				p = &ioport_resource;
		}

		if (p && insert_resource(p, r)) {
			printk(KERN_ERR
			       "%s: failed to claim resource %d\n",
			       dev_name(&pdev->dev), i);
			ret = -EBUSY;
			goto failed;
		}
	}

	pr_debug("Registering platform device '%s'. Parent at %s\n",
			dev_name(&pdev->dev), dev_name(pdev->dev.parent));

	ret = device_add(&pdev->dev);	//添加设备文件
	if (ret == 0)
		return ret;

 failed:
	while (--i >= 0) {
		struct resource *r = &pdev->resource[i];
		unsigned long type = resource_type(r);

		if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
			release_resource(r);
	}

	return ret;
}

    2.2 平台设备的注册一般放在Board-xxx.c板级驱动中

对于多个平台设备需要注册 可以定义一个数组如下:

static struct platform_device platform_device_1 = {
	.name	= "paltform_1",
	.id	= -1,				//设备id一般都设置为-1
	.num_resources = 0,
    .dev = {
		.platform_data = &paltform_1_pdata,
    }
}; 

static struct platform_device platform_device_2 = {
	.name	= "paltform_2",
	.id	= -1,
	.resource = &paltform_2_resource,		//平台资源
	.num_resources = 1,			//平台资源数
};
	....
static struct platform_device *test_devices[] __initdata = {
	&platform_device_1,
	&platform_device_2,
	&platform_device_3,
};

然后在其板级驱动.init_machine指定的初始化函数中注册 如下:

//分别注册
platform_device_register(&platform_device_1);
platform_device_register(&platform_device_2);
platform_device_register(&platform_device_3);
//或者一次性注册
platform_add_devices(test_devices,ARRAY_SIZE(test_devices))

    2.3 使用platform_add_devices同时注册多个平台设备

int platform_add_devices(struct platform_device **devs, int num)
{
	int i, ret = 0;

	for (i = 0; i < num; i++) {
		ret = platform_device_register(devs[i]);	//可以看到它只是多次调用platform_device_register而已
		if (ret) {
			while (--i >= 0)
				platform_device_unregister(devs[i]);
			break;
		}
	}

	return ret;
}

 

    2.4 平台设备动态创建 platform_device_alloc

struct platform_device *platform_device_alloc(const char *name, int id)
{
	struct platform_object *pa;

	pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
	if (pa) {
		strcpy(pa->name, name);
		pa->pdev.name = pa->name;				//设置平台设备的.name域
		pa->pdev.id = id;					//设置平台设备的.id域
		device_initialize(&pa->pdev.dev);
		pa->pdev.dev.release = platform_device_release;
	}

	return pa ? &pa->pdev : NULL;
}

 

    3.平台设备注销

void platform_device_unregister(struct platform_device *pdev)
{
	platform_device_del(pdev);
	platform_device_put(pdev);
}

 

三. 平台驱动

   1.平台驱动结构体

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;	//设备驱动文件
	const struct platform_device_id *id_table;	//支持的设备id表
};

 

    2.平台驱动注册

int platform_driver_register(struct platform_driver *drv)
{
	drv->driver.bus = &platform_bus_type;	//设置平台驱动总线类型
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;	//设置probe方法
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;	//设置remove方法
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;	//设置shutdown方法

	return driver_register(&drv->driver);	//注册设备文件
}


    2.1 platform_drv_probe

static int platform_drv_probe(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);	//通过设备文件获取平台驱动
	struct platform_device *dev = to_platform_device(_dev);	//通过设备文件获取平台设备

	return drv->probe(dev);	//调用平台驱动的probe方法
}


    2.2 platform_drv_remove

static int platform_drv_remove(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);	//通过设备文件获取平台驱动
	struct platform_device *dev = to_platform_device(_dev);	//通过设备文件获取平台设备

	return drv->remove(dev);	//调用平台驱动的remove方法
}

 

    2.3 platform_drv_shutdown

static void platform_drv_shutdown(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);	//通过设备文件获取平台驱动
	struct platform_device *dev = to_platform_device(_dev);	//通过设备文件获取平台设备

	drv->shutdown(dev);	//调用平台驱动的shutdown方法
}

 

    2.4 平台驱动放在对应的驱动目录下

平台驱动和平台设备的.name域应该相同才能给平台总线匹配match上,才会调用平台驱动的probe方法

平台资源的获取一般放在probe方法中,使用platform_get_resource获取

 

    2.5 上面提到的平台驱动注册方式是针对支持热拔插设备的,不支持热插拔的设备用platform_driver_probe注册

int __init_or_module platform_driver_probe(struct platform_driver *drv,int (*probe)(struct platform_device *))
{
	int retval, code;

	/* make sure driver won't have bind/unbind attributes */
	drv->driver.suppress_bind_attrs = true;

	/* temporary section violation during probe() */
	drv->probe = probe;	//这里把probe函数设置为平台驱动的probe方法,所以使用此方法时平台驱动结构体不要先指定其probe域
	retval = code = platform_driver_register(drv);

	/*
	 * Fixup that section violation, being paranoid about code scanning
	 * the list of drivers in order to probe new devices.  Check to see
	 * if the probe was successful, and make sure any forced probes of
	 * new devices fail.
	 */
	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
	drv->probe = NULL;
	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
		retval = -ENODEV;
	drv->driver.probe = platform_drv_probe_fail;
	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);

	if (code != retval)
		platform_driver_unregister(drv);
	return retval;
}

 

    3. 平台驱动注销

void platform_driver_unregister(struct platform_driver *drv)
{
	driver_unregister(&drv->driver);
}


四. 平台资源

   1.资源结构体

struct resource {
	resource_size_t start;	//资源起始物理地址
	resource_size_t end;	//资源结束物理地址
	const char *name;		//资源名
	unsigned long flags;	//资源类型
	struct resource *parent, *sibling, *child;
};

    1.1 常用的资源类型有:

#define IORESOURCE_IO		0x00000100		//io资源
#define IORESOURCE_MEM		0x00000200		//内存资源
#define IORESOURCE_IRQ		0x00000400		//中断资源

    1.2 平台资源的获取
参数是:资源所属的平台设备,获取资源的类型,获取的资源个数

struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num)
{
	int i;

	for (i = 0; i < dev->num_resources; i++) {
		struct resource *r = &dev->resource[i];

		if (type == resource_type(r) && num-- == 0)
			return r;
	}
	return NULL;
}


 

 

你可能感兴趣的:(linux platform平台设备驱动)