基于smart210的LED驱动(platform机制)

1. 使用platform机制,编写LED驱动层
首先创建设备代码和驱动代码:led_dev.c 、led_drv.c

led_dev.c用来指定灯的引脚地址,当更换平台时,只需要修改这个就行

led_drv.c用来初始化灯以及如何控制灯的逻辑,当更换控制逻辑时,只需要修改这个就行

2.编写led.dev.c
2.1编写led_dev.c之前先来看看platform_device结构体和要使用的函数:
platform_device结构体如下:

struct platform_device {
  const char       * name;           //设备名称,要与platform_driver的name一样,这样总线才能匹配成功
  u32          id;                   //id号,插入总线下相同name的设备编号(一个驱动可以有多个设备),如果只有一个设备填-1
  struct  device  dev;               //内嵌的具体的device结构体,其中成员platform_data,是个void *类型,可以给平台driver提供各种数据(比如:GPIO引脚等等)
  u32 num_resources;                 //资源数量,
  struct resource         * resource;    //资源结构体,保存设备的信息
};

其中resource资源结构体,如下:

struct resource {
         resource_size_t start;                    //起始资源,如果是地址的话,必须是物理地址
         resource_size_t end;                      //结束资源,如果是地址的话,必须是物理地址
         const char *name;                         //资源名
         unsigned long flags;                      //资源的标志
         //比如IORESOURCE_MEM,表示地址资源, IORESOURCE_IRQ表示中断引脚... ...

         struct resource *parent, *sibling, *child;   //资源拓扑指针父、兄、子,可以构成链表
};

要用的函数如下,在dev设备的入口出口函数中用到
int platform_device_register(struct platform_device * pdev); //注册dev设备
int platform_device_unregister(struct platform_device * pdev); //注销dev设备
在这里插入图片描述
2.2代码如下

 /*GPFCON 0xE0200280//本驱动使用,注意unsigned long 为4字节(4*8 bit),相当与ff
      GPFDAT 0xE0200284/本驱动使用
      GPFUP 0xE0200288//本驱动不使用,上拉电阻在驱动中不使用到,
      */
static struct resource	led_resource[] = {
	[0] = {
		.start	=	0xE0200280,
		.end	= 	0xE0200280 + 8 - 1,
		.flags 	=	IORESOURCE_MEM,
	},
	[1] = {
		.start	= 	0,
		.end	=	0,
		.flags	=	IORESOURCE_IRQ,
	},
};
static void led_release(struct device *dev)
{
}
static struct platform_device led_dev = {
	.name	= "myled",
	.id		= -1,
	.num_resources	= ARRAY_SIZE(led_resource),
	.resource		= led_resource,
	.dev	={
		.release = led_release,
	},
};



static int __init led_dev_init(void)
{
	platform_device_register(&led_dev);
	return 0;
}

static void __exit	led_dev_exit(void)
{
	platform_device_unregister(&led_dev);
}

3.编写led.drv.c
3.1编写led_dev.c之前先来看看platform_device结构体和要使用的函数:

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 (*suspend_late)(struct platform_device *, pm_message_t state);
       int (*resume_early)(struct platform_device *);
       int (*resume)(struct platform_device *);           //唤醒
       struct device_driver driver;       //内嵌的driver,其中的name成员要等于设备的名称才能匹配

};



int platform_driver_register(struct platform_driver *drv);     //注册驱动
platform_driver_unregister(struct platform_driver *drv);    //卸载驱动

struct resource * platform_get_resource(struct platform_device *dev, unsigned int type,unsigned int num);
//获取设备的某个资源,获取成功,则返回一个resource资源结构体
//参数:
// *dev :指向某个platform device设备
// type:获取的资源类型
// num: type资源下的第几个数组

3.2先写要注册的led驱动:platform_driver结构体

/*函数声明*/
static  int  led_remove(struct platform_device *led_dev);
static  int led_probe(struct platform_device *led_dev);

struct platform_driver led_drv = {
       .probe           = led_probe,        //当与设备匹配,则调用该函数
       .remove         = led_remove,             //删除设备

       .driver            = {
              .name     = "myled",           //与设备名称一样
       }
};

3.3写file_operations 结构体、以及成员函数(.open、.write)、.probe函数、
当驱动和设备都insmod加载后,然后bus总线会匹配成功,就进入.probe函数,

在.probe函数中便使用platform_get_resource()函数获取LED的地址和引脚,然后初始化LED,并注册字符设备和设备节点"led"

tatic int major;
static struct class *cls;
static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;
static int pin;

static int led_open(struct inode *inode,struct file *file)
{
	*gpio_con	&=	~(0xf<<(pin*4));
	*gpio_con	|=	(0x1<<(pin*4));
	return 0;
}

static ssize_t led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
	int val = 0;
	copy_from_user(&val,buf,count);
	if(val == 1)
	{
		*gpio_dat &= ~(1<<pin);

	}
	else 
	{
		*gpio_dat |= (1<<pin);
	}
	return 0;
}

static struct file_operations led_fops = {
	.owner	=	THIS_MODULE,
	.open	=	led_open,
	.write	=	led_write,
};
static int led_probe(struct platform_device *pdev)
{
	struct resource	*res;
	
	res = platform_get_resource(pdev,IORESOURCE_MEM,0);//获得第0+1个IORESOURCE_MEM资源
	gpio_con = ioremap(res->start,res->end - res->start + 1);
	gpio_dat = gpio_con + 1;
	res = platform_get_resource(pdev,IORESOURCE_IRQ,0);//获得第0+1个IORESOURCE_IRQ资源
	pin = res->start;
	printk("led_probe, found led\n");
	major = register_chrdev(0,"myled",&led_fops);
	cls = class_create(THIS_MODULE,"myled");
	device_create(cls,NULL,MKDEV(major,0),NULL,"led");//   /dev/led
	return 0;
}

struct platform_driver led_drv = {
	.probe	=	led_probe,
	.remove	=	led_remove,
	.driver	=	{
		.name	=	"myled",
	},
};

3.4写.remove函数
如果驱动与设备已联系起来,当卸载驱动时,就会调用.remove函数卸载设备和.probe函数一样,注册了什么就卸载什么便可

static int led_remove(struct platform_device *pdev)
{
       /* 卸载字符设备驱动程序 */
       printk("enter remove\n");
       class_device_destroy(cls, MKDEV(major, 0));
       class_destroy(cls);
       unregister_chrdev(major, "myled");

       iounmap(gpio_con);       //注销虚拟地址
       return 0;
}

3.5最后写drv的入口出口函数

static int led_drv_init(void)           //入口函数,注册驱动
{
       platform_driver_register(&led_drv);
       return 0;
} 
static void led_drv_exit(void)       //出口函数,卸载驱动
{
       platform_driver_unregister(&led_drv);
}

module_init(led_drv_init);     
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");

4.测试
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值