> 文章列表 > Platform虚拟总线(设备驱动分离详解)

Platform虚拟总线(设备驱动分离详解)

Platform虚拟总线(设备驱动分离详解)

目录

 1.驱动结构体​编辑

C语言语法:

(struct platform_device *)

platform驱动编写 

2.设备结构体


 1.驱动结构体

 led驱动配置      

   platform_device是device的子类,设备数据类型为device,通过device_register向内核注册设备,注册设备时,名字相同时匹配成功,驱动与设备匹配以后驱动的probe函数就会执行。

C语言语法:

int (*probe)(struct platform_device *);

是一个函数指针,可以令probe = func,从而指代一个函数名来调用。

(struct platform_device *)

是指调用这个函数时的参数是一个结构体指针struct platform_device *。 

platform驱动编写 

(1)注册模板,驱动名字匹配 

/* platform驱动结构体 */
static struct platform_driver led_driver = {.driver		= {.name	= "imx6ul-led",			/* 驱动名字,用于和设备匹配 */},.probe		= led_probe,.remove		= led_remove,
};static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);
}module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zyx");

(2)编写led_probe和led_exit函数 

static int led_probe(struct platform_device *dev)
{	int i = 0;int ressize[5];u32 val = 0;struct resource *ledsource[5];printk("led driver and device has matched!\\r\\n");/* 1、获取资源 */for (i = 0; i < 5; i++) {ledsource[i] = platform_get_resource(dev, IORESOURCE_MEM, i); /* 依次MEM类型资源*/if (!ledsource[i]) {dev_err(&dev->dev, "No MEM resource for always on\\n");return -ENXIO;}ressize[i] = resource_size(ledsource[i]);	}	/* 2、初始化LED *//* 寄存器地址映射 */IMX6U_CCM_CCGR1 = ioremap(ledsource[0]->start, ressize[0]);SW_MUX_GPIO1_IO03 = ioremap(ledsource[1]->start, ressize[1]);SW_PAD_GPIO1_IO03 = ioremap(ledsource[2]->start, ressize[2]);GPIO1_DR = ioremap(ledsource[3]->start, ressize[3]);GPIO1_GDIR = ioremap(ledsource[4]->start, ressize[4]);val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26);				/* 清除以前的设置 */val |= (3 << 26);				/* 设置新值 */writel(val, IMX6U_CCM_CCGR1);/* 设置GPIO1_IO03复用功能,将其复用为GPIO1_IO03 */writel(5, SW_MUX_GPIO1_IO03);writel(0x10B0, SW_PAD_GPIO1_IO03);/* 设置GPIO1_IO03为输出功能 */val = readl(GPIO1_GDIR);val &= ~(1 << 3);			/* 清除以前的设置 */val |= (1 << 3);			/* 设置为输出 */writel(val, GPIO1_GDIR);/* 默认关闭LED1 */val = readl(GPIO1_DR);val |= (1 << 3) ;	writel(val, GPIO1_DR);/* 注册字符设备驱动 *//*1、创建设备号 */if (leddev.major) {		/*  定义了设备号 */leddev.devid = MKDEV(leddev.major, 0);register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);} else {						/* 没有定义设备号 */alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);	/* 申请设备号 */leddev.major = MAJOR(leddev.devid);	/* 获取分配号的主设备号 */}/* 2、初始化cdev */leddev.cdev.owner = THIS_MODULE;cdev_init(&leddev.cdev, &led_fops);/* 3、添加一个cdev */cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);/* 4、创建类 */leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);if (IS_ERR(leddev.class)) {return PTR_ERR(leddev.class);}/* 5、创建设备 */leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);if (IS_ERR(leddev.device)) {return PTR_ERR(leddev.device);}return 0;
}static int led_remove(struct platform_device *dev){iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);cdev_del(&leddev.cdev);/*  删除cdev */unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */device_destroy(leddev.class, leddev.devid);class_destroy(leddev.class);return 0;
}

2.设备结构体

 

1、无设备树的时候,此时需要驱动开发人员编写设备注册文件,使用platform_device_register函数注册设备,最终执行probe函数

2、有设备树,修改设备树的设备节点即可,当设备与platform的驱动匹配以后,就会执行platform_driver->probe函数。

未完待续。。。。。。