三、LED-总线驱动模型
(1)总线设备驱动模型(Linux/base)
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;
};
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;//所支持的一个或多个设备名
};
Driver如何从Device中获得指定的资源(匹配)
通过.match= platform_match
来匹配,若(Dev,Dir)匹配则调用platform_driver中的probe函数
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};
细节-名字很重要
platform_driver:platform_device_id**中的 char name[PLATFORM_NAME_SIZE];
device_driver 中的 *const char name;
platform_device:****const char * name;
匹配
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))//open firm使用设备树匹配
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;//使用id_table名字进行匹配
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);//或者使用最简单的方法比较平台设备的名字和 //DRV的名字故优先比较id table
}
static const struct platform_device_id *platform_match_id(
const struct platform_device_id *id,
struct platform_device *pdev)
{
while (id->name[0]) {
if (strcmp(pdev->name, id->name) == 0) { //通过名字匹配
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
}
(2)实例操作
Dev代码
? 指定platform_device结构体并注册
static struct platform_device led_dev=
{
.name = "my_led",
.id = -1, //表示只有一个设备
.num_resources = ARRAY_SIZE(led_resouce),
.resource = led_resouce,
.dev=
{
.release = led_dev_release,
},
};
static int led_dev_init(void)
{
printk("led_dev init\n");
platform_device_register(&led_dev);
return 0;
}
static void led_dev_exit(void)
{
printk("led_dev exit\n");
platform_device_unregister(&led_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
//#define CCM_CCGR1 0x20C406C;
//#define IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 0x2290014;
//#define GPIO5_GDIR 0x020AC000;
//#define GPIO5_DR 0x020AC000;
static struct resource led_resouce[]= //指定资源
{
[0]={
.start = 0x20C406C,
.end = 0x20C406C+4-1,
.flags = IORESOURCE_MEM,
},
[1]={
.start = 0x2290014,
.end = 0x2290014+4-1,
.flags = IORESOURCE_MEM,
},
[2]={
.start = 0x020AC000,
.end = 0x020AC000+4-1,
.flags = IORESOURCE_MEM,
},
[3]={
.start = 0x020AC000,
.end = 0x020AC000+4-1,
.flags = IORESOURCE_MEM,
},
};
Drv代码
static struct platform_driver chip_gpio_drv = {
.probe = chip_gpio_led_probe,
.remove = chip_gpio_led_remove,
.driver = {
.name = "my_led",
},
};
static int chip_gpio_led_probe(struct platform_device *dev)
{
struct resource *CCM;
struct resource *IOMUXC_SNVS_SW_MUX;
struct resource *GDIR;
struct resource *DR;
CCM = platform_get_resource(dev,IORESOURCE_MEM,0);
IOMUXC_SNVS_SW_MUX = platform_get_resource(dev,IORESOURCE_MEM,1);
GDIR = platform_get_resource(dev,IORESOURCE_MEM,2);
DR = platform_get_resource(dev,IORESOURCE_MEM,3);
CCM_CCGR1 = ioremap(CCM->start, CCM->end - CCM->start + 1);
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(IOMUXC_SNVS_SW_MUX->start, IOMUXC_SNVS_SW_MUX->end - IOMUXC_SNVS_SW_MUX->start + 1);
GPIO5_GDIR = ioremap(GDIR->start, GDIR->end - GDIR->start + 1);
GPIO5_DR = ioremap(DR->start, DR->end - DR->start + 1);
major=register_chrdev(0,"100ask_led",&led_drv);
led_class = class_create(THIS_MODULE, "100ask_led");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "led");
printk("led platform driver probe\n");
return 0;
}
static int chip_gpio_led_remove(struct platform_device *dev)
{
printk(" remove led\n");
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "100ask_led");
iounmap(CCM_CCGR1);
iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
iounmap(GPIO5_GDIR);
iounmap(GPIO5_DR);
return 0;
}
static struct file_operations led_drv = {
.owner = THIS_MODULE,
.open = led_drv_open,
.read = led_drv_read,
.write = led_drv_write,
.release = led_drv_close,
};
/* 1. 实现对应的open/read/write等函数,填入file_operations结构体 */
static int major=0;
static struct class *led_class;
static volatile unsigned long *CCM_CCGR1;
static volatile unsigned long *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
static volatile unsigned long *GPIO5_GDIR;
static volatile unsigned long *GPIO5_DR;
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
return 0;
}
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int value;
int err;
err=copy_from_user(&value,buf,1);
if (value) /* on: output 0*/
{
*GPIO5_DR &= ~(1<<3);
printk(" on: output 0*\n");
}
else /* off: output 1*/
{
*GPIO5_DR |= (1<<3);
printk(" off: output 1*\n");
}
printk("%d\n",err);
return 1;
}
static int led_drv_open (struct inode *inode, struct file *file)
{
unsigned int val;
// printk("%s\n", __func__);
*CCM_CCGR1 |= (3<<30);
val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
val &= ~(0xf);
val |= (5);
*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;
*GPIO5_GDIR |= (1<<3);
return 0;
}
static int led_drv_close (struct inode *inode, struct file *file)
{
return 0;
}
测试运行
先挂载dev设备模块 , 在platform/devices目录下生成一个"my_led"设备
ls /sys/bus/platform/devices/
再来挂载drv驱动模块 , 在platform/drivers目录下生成一个"my_led"驱动 ,匹配成功调用probe函数。
ls /sys/bus/platform/drivers/
原文:https://www.cnblogs.com/imunrobot/p/12883598.html