platform总线设备与驱动

目录

  1. platform总线、设备、驱动
  2. platform设备
  3. platform总线
  4. platform驱动

platform总线、设备、驱动

Linux2.6以后的设备驱动模型中,需要关注总线设备和驱动这三个实体,总线将设备和驱动绑定,在系统注册一个设备的时候,总线会去匹配驱动,注册驱动的时候,总线回去匹配相应的设备,匹配工作由总线完成

Linux中有一种总线叫做platform总线,相应的设备称作platform_device,相应的驱动称作platform_driver,所谓的“platform_device”并不是与字符设备、块设备和网络设备并列的概念,而是Linux 系统提供的一种附加手段,例如,在S3C2410 处理器中,把内部集成的I2C、IIS、RTC、看门狗等都归纳为平台设备,而它们本身就是字符设备。

platform设备

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;

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

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

linux2.6ARM平台而言,对platform_device的定义通常在bsp的板文件中定义在板文件中,将platform_device归纳为一个数组,最终通过函数platform_add_devices将设备添加到系统中。函数原型如下所示

int platform_add_devices(struct platform_device **devs, int num)

函数的第一个参数为平台设备数组的指针,第二个参数为平台设备的数量。

linux3.x之后的版本中,人们更倾向于在设备树中添加平台设备

假设我们定义一个platform_device如下所示:

#define PIN_BASE        32
#define CHIPSELECT_2	0x30000000
#define PIN_PC11	    (PIN_BASE + 0x40 + 11)
#define GPIO_PF9	    9
#define CH_SPI          5
#define DATA_FLAG       5

static struct resource globalmem_resoure[] = {
	[0] = {
		.start	= CHIPSELECT_2,
		.end	= CHIPSELECT_2 + 3,
		.flags	= IORESOURCE_MEM
	},
	[1] = {
		.start	= CHIPSELECT_2 + 0x44,
		.end	= CHIPSELECT_2 + 0xFF,
		.flags	= IORESOURCE_MEM
	},
	[2] = {
		.start	= PIN_PC11,
		.end	= PIN_PC11,
		.flags	= IORESOURCE_IRQ
			| IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE,
	},
	[3] = {
		.start = GPIO_PF9,
		.end = GPIO_PF9,
		.flags = IORESOURCE_IO,
	},
    [4] = {
        .start = CH_SPI,
        .end   = CH_SPI,
        .flags = IORESOURCE_DMA,
    },
};

struct plat_platform {
    unsigned long   iobase;     /* io base address */
    unsigned int    irq;        /* interrupt number */
    unsigned int    clk;    /* UART clock rate */
    int       flags;      /* UPF_* flags */

};

#define PORT(base, int)							\
{                                   \
    .iobase     = base,                     \
    .irq        = int,                      \
    .clk        = 1843200,                  \
    .flags      = DATA_FLAG,        \
}

static struct plat_platform platform_data[] = {
    PORT(0x3F8, 4),
    PORT(0x2F8, 3),
    PORT(0x3E8, 4),
    PORT(0x2E8, 3),
    { },
};
static struct platform_device platform_uart_device2 = {
    .name = "globalfifo",
    .id = -1,
    .resource = globalmem_resoure,
    .num_resources = ARRAY_SIZE(globalmem_resoure),
    .dev = {
        .platform_data = platform_data,
    }
};

#define PA_IIC1		0xEC20F000
#define IRQ_IIC1		((5) + 32)

static struct resource i2c_resource[] = {
    [0] = {
        .start = PA_IIC1,
        .end   = PA_IIC1 + SZ_4K - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = IRQ_IIC1,
        .end   = IRQ_IIC1,
        .flags = IORESOURCE_IRQ,
    },
};

struct platform_device device_i2c1 = {
    .name         = "s3c2410-i2c",
    .id       = -1,
    .num_resources    = ARRAY_SIZE(i2c_resource),
    .resource     = i2c_resource,
};

#define PA_USBDEV	(0x15200140)
#define SZ_USBDEV   SZ_1M
#define IRQ_USBD	        18
static struct resource usbgadget_resource[] = {
	[0] = {
		.start = PA_USBDEV,
		.end   = PA_USBDEV + SZ_USBDEV - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_USBD,
		.end   = IRQ_USBD,
		.flags = IORESOURCE_IRQ,
	}

};

struct platform_device device_usbgadget = {
	.name		  = "s3c2410-usbgadget",
	.id		  = -1,
	.num_resources	  = ARRAY_SIZE(usbgadget_resource),
	.resource	  = usbgadget_resource,
};

struct platform_device *globaofifo_device[3] = {
    &platform_uart_device2,
    &device_i2c1,
    &device_usbgadget,
};

EXPORT_SYMBOL(globaofifo_device);

通过下面的函数将设备添加到系统中

ret = platform_add_devices(globaofifo_device, 3);

platform总线

每一个总线都有一个bus_type的实例,platform为platform_bus_type,其中最重的成员为match函数,这个函数为设备和驱动的匹配函数,即前面提过的宗献中用于匹配设备和驱动的函数match

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_attrs	= platform_dev_attrs,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};

match主要完成一项工作,就是匹配platform_device和platform_driver,当platform_device和platform_driver匹配成功之后,会调用platform_drivber的probe函数,大部分驱动的初始化工作都是在probe函数中执行。匹配方式有四种:

  1. 基于设备树的风格匹配
  2. 基于ACPI的风格匹配
  3. 匹配id表,即platform_device设备名是否出现在platform_driver的id表中
  4. 匹配platform_device设备名和驱动的名字
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);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

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

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

platform驱动

platform_driver结构体如下所示,主要函数为probe和remove函数,一个device_driver实例,和platform_driver地位对等的i2c_driver、spi_driver中都包含了device_driver结构体实例成员,他描述了各种总线在驱动意义上的一些共性

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;
};

platform的匹配id表驱动代码如下所示

static int globalfifo_probe(struct platform_device *pdev)
{
    int ret;
    struct resource *res_mem[2];
    struct resource *res_irq;
    struct resource *res_io;
    struct resource *res_dma;
    struct plat_platform *platform_data;

    ret = misc_register(&zt_misc);

	globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);

	mutex_init(&globalmem_devp->mutex);
	return 0;

fail_malloc:
    misc_deregister(&zt_misc);
    return ret;
}


static int globalfifo_remove(struct platform_device *pdev)
{
    misc_deregister(&zt_misc);
	kfree(globalmem_devp);
	return 0;
}

static struct platform_device_id platform_device_ids[] = {
	{
		.name = "globalfifo",
	},
	{}
};

static struct platform_driver globaofifo_driver = {
	.driver		= {
		.name	= "globalfifozhang",
        .owner   = THIS_MODULE,
	},
	.probe		= globalfifo_probe,
	.remove		= globalfifo_remove,
    .id_table   = platform_device_ids,

};
static int __init platform_init(void)
{
    return platform_driver_register(&globaofifo_driver);
}

static void __exit platform_exit(void)
{
    platform_driver_unregister(&globaofifo_driver);

}

module_init(platform_init);
module_exit(platform_exit);
MODULE_LICENSE("GPL");

platform的匹配platform_device设备名和驱动的名字驱动代码如下所示

static int globalfifo_probe(struct platform_device *pdev)
{
    int ret;
    struct resource *res_mem[2];
    struct resource *res_irq;
    struct resource *res_io;
    struct resource *res_dma;
    struct plat_platform *platform_data;

    ret = misc_register(&zt_misc);

	globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);

	if (!globalmem_devp) {
		ret = -ENOMEM;
		goto fail_malloc;
	}

	mutex_init(&globalmem_devp->mutex);
	return 0;

fail_malloc:
    misc_deregister(&zt_misc);
    return ret;
}


static int globalfifo_remove(struct platform_device *pdev)
{
    misc_deregister(&zt_misc);
	kfree(globalmem_devp);
	return 0;
}

static struct platform_driver globaofifo_driver = {
	.driver		= {
		.name	= "globalfifo",//驱动名字
        .owner   = THIS_MODULE,
	},
	.probe		= globalfifo_probe,
	.remove		= globalfifo_remove,

};
static int __init platform_init(void)
{
    return platform_driver_register(&globaofifo_driver);
}

static void __exit platform_exit(void)
{
    platform_driver_unregister(&globaofifo_driver);

}

module_init(platform_init);
module_exit(platform_exit);
MODULE_LICENSE("GPL");

下一篇:platform设备资源与数据:https://blog.csdn.net/qq_37600027/article/details/100803447

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值