platform和设备树驱动蜂鸣器

目录

1.plat_fom介绍:

2.设备树介绍:

3.实现过程:

1.设备树:(以exynos-fs4412为例)

2.平台驱动:

3.驱动的启动函数:  

4.驱动卸载


1.platform介绍:

        从Linux2.6开始Linux加入了一套驱动管理和注册机制—platform总线驱动模型。platform总线是一条虚拟总线(只有一条),这类总线没有对应的硬件结构platform_device为相应的设备,platform_driver为相应的驱动。与传统的bus/device/driver机制相比,platform由内核统一进行管理,提高了代码的可移植性和安全性。

优点:

1.可以通过platform总线,可以遍历所有的platform总线设备;platform本质其实也是kset、  kobject,具有kobject的特性;
2.实现设备与驱动的分离,通过platform总线,设备与驱动是分开注册的,通过platform总线的  probe来随时检测与设备匹配的驱动,如匹配上即进行这个设备的驱动注册;
3.一个驱动可以供同类的几个设备使用;

2.设备树介绍:

          设备树是一种描述硬件得数据结构,在操作系统引导阶段进行设备初始化得时候,数据结构中得硬件信息被检测并传递给操作系统。

          Liunx内核从3.x开始引入设备树得概念,用于实现驱动代码与设备信息相分离。在设备树出现之前,所有关于设备得具体信息都要写在驱动里面,一旦外围设备变化,驱动代码就要重写。引入设备树后,驱动代码只负责处理驱动得逻辑,而关于设备具体信息要存放到设备树文件中。

          这样,如果只是硬件接口信息得变化而没有驱动逻辑得变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。

3.实现过程:

1.设备树:(以exynos-fs4412为例)

        首先在设备树文件中添加蜂鸣器的设备节点,同时添加对应寄存器地址,由于设备树可以自动遍历查找地址,所以只需填写一个地址范围,包含所有的寄存器就行。compatible ="fs,mybee"而这句话就代表一种匹配规则。

mybee@11000ca0{
	compatible ="fs,mybee";
	reg = <0x11000a40 0x4>,<0x139d0000 0x14>;
};

2.平台驱动:

1)首先我们可以搭建一个平台驱动的基本框架,框架如下,我们在对应的位置填入对应的代码。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <asm/io.h>

struct of_device_id of_matches[]={
                                                //修改匹配规则,从设备树                                                                                     
                                                 //获取buzzer相关硬件信息
};
static struct platform_driver mydriver ={
                                                //通过设备树匹配
    
};  
static int mod_init(void)
{
    return  platform_driver_register(&mydriver);  //平台驱动注册
}
static void mod_exit(void)
{
    platform_driver_unregister(&mydriver);        //平台驱动注销
}

module_init(mod_init);
module_exit(mod_exit);
MODULE_LICENSE("GPL");

2)我们修改匹配机制,从设备树匹配,配诶规则一定要和我们写的设备树中的规则一致。

struct of_device_id of_matches[]={
    {.compatible="fs,mybee"},           //修改匹配规则,从设备树  
    {},                                 //获取buzzer相关硬件信息
};

3) paltform选择匹配方式:

static struct platform_driver mydriver ={
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "mytest",               
        .of_match_table =  of_matches,  //通过设备树匹配
    },
    
};  

3.驱动的启动函数:  

      前面的准备工作完成后,从设备树中获取设备的信息,就需要将字符设备注册到内核中,首先将所需的寄存器物理地址映射为虚拟地址,然后进行字符设备的注册,首先申请设备号,然后cdev初始化,紧接着将cdev添加到内核,当所有步骤完成后就可以添加硬件操作的函数了。

int my_probe(struct platform_device *pdev)
{
    int ret;
    //通过设备树获取硬件资源
    printk( "match\n");

    //0代表匹配的设备树第0个地址为基地址
    rescon = platform_ get_ resource (pdev , IORESOURCE MEM, 0);
    if ( rescon=-NULL){
    goto failed_ getcon;
    }
    resdata = platform get_ resource (pdev , IORESOURCE MEM,1) ;
    if ( resdata==NULL ){
    goto failed_ getdata;
    gpd0con = ioremap( rescon->start,4);
    //利用设备树获取各个寄存器的地址
    tcfg0 = ioremap( resdata->start,4) ;
    tcfg1 = ioremap ( resdata->start+4,4) ;
    tcon = ioremap( resdata->start+8,4);
    tcntb0 = ioremap ( resdata->start+12,4);
    tcmpb0 = ioremap( resdata->start+16,4);

    //字符设备注册
    ret =  alloc_chrdev_region(&devnum,0,1,name);//1.申请设备号
    if(ret!=0){
        goto failed_alloc;
    }
    cdev_init(&mycdev,&myops); //2.cdev初始化

    ret = cdev_add(&mycdev,devnum,1); //3.cdev添加到内核
    if(ret!=0){
        goto failed_add;
    }
    printk("register success %d,%d\n",MAJOR(devnum),MINOR(devnum));

    myclass = class_create(THIS_MODULE,"myclass");
    if(IS_ERR(myclass)){
        goto failed_class;
    }
    mydevice = device_create(myclass,NULL,devnum,NULL,"buzzer");
    if(IS_ERR(mydevice)){
        goto failed_device;
    }
    //硬件操作
    buzzer_init();
    buzzer_off();

    return 0;

failed_device:
    class_destroy(myclass);
failed_class:
    cdev_del(&mycdev);
failed_add:
    unregister_chrdev_region(devnum,1);
failed_alloc:
    return -1;
}

4.驱动卸载

        现将所有的寄存器解除映射,释放设备号,释放设备对象,删除设备,将设备从内核中注销。

int my_remove(struct platform_device *pdev)
{
    printk("driver remove\n");
    iounmap(gpd0con);
    iounmap(tcfg0);
    iounmap(tcfg1);
    iounmap(tcon);
    iounmap(tcntb0);
    iounmap(tcmpb0);

    device_destroy(myclass,devnum);
    class_destroy(myclass);
    cdev_del(&mycdev);
    unregister_chrdev_region(devnum,1);

    return 0;
}

        这样就基本完成了整个蜂鸣器的驱动编写,希望有帮助!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值