首页 > 其他 > 详细

三、LED-总线驱动模型

时间:2020-05-13 17:51:18      阅读:51      评论:0      收藏:0      [点我收藏+]

三、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_driverplatform_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代码

      1. ? 指定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代码

          1. ? 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;
          }
          
          1. 驱动核心(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;
          }
          
          1. 测试运行

            先挂载dev设备模块 , 在platform/devices目录下生成一个"my_led"设备

             ls /sys/bus/platform/devices/
            

            再来挂载drv驱动模块 , 在platform/drivers目录下生成一个"my_led"驱动 ,匹配成功调用probe函数。

             ls /sys/bus/platform/drivers/
            

三、LED-总线驱动模型

原文:https://www.cnblogs.com/imunrobot/p/12883598.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!