三、LED-总线驱动模型
三、LED-总线驱动模型
(1)总线设备驱动模型(Linux/base)
- 将Device(指定硬件资源)、Driver(分配、设置、注册file_operation结构体、根据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;
};
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代码
- platform_driver结构体
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; }- 驱动核心(file_operation结构体)
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/
-
-
-

浙公网安备 33010602011771号