3.X内核下设备树–platform设备驱动

1。历史的车轮总是向前,技术更替。在linus 同学发出那句 WFK 后内核进入了设备树时代(站在驱动工程师角度)。

前几天我已经被mach-imx 中的文件折磨的夜不能眠。我终于在一个清晨,喝完一杯咖啡后决定放弃蹩脚的传统device描述方式。

这里我先不讨论内核实现流程的源代码,简单描述下语法,和我的第一个test_platform_device

设备树文件 arch\arm\boot\dts 在修改dst文件后要make dtbs,

http://www.xuebuyuan.com/2128963.html 这篇文章可以恶补下设备书的基础

如图是一个完整节点
这里写图片描述
这里写图片描述

Documentation\devicetree\bindings 文件夹中有很多的样例可以供开发人员参考

2。 我的测试

我在我的设备树中添加如下代码(这里我把一个ds18b20做成platform设备,仅仅为了练习)
这里写图片描述

    my-ds18b20 {

        compatible = "ds18b20";
        gpios = <&gpio2 3 1>;   //有更改,以这里为准

        };

我ds18b20使用的是GPIO2_3 管脚。

这里的gpios = <&gpio2 3 0>; 在 imx6qdl.dtsi 文件中定义
这里写图片描述
然后执行 # make dtbs

生成的dtbs文件在dts文件同一目录,烧写 内核 和 DTBS 文件

编写ds18b20的driver 端(为了使结构简单明了,我屏蔽了其他代码,留下了骨架)

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>




static int ds18b20_probe(struct platform_device *pdev)
{

    struct resource *addr_res = NULL;   /* resources found */

    printk("probe!!!!!!!!!! \n");

    addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

    if (addr_res == NULL) printk("get_re error");

    return 0;
}


static int ds18b20_drv_remove(struct platform_device *pdev)
{

    return 0;
}


static const struct of_device_id ds18b20_of_matches[] = {
    { .compatible = "my-ds18b20", },    //和dts文件中名字匹配
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ds18b20_of_matches);



static struct platform_driver ds18b20_driver = {
    .driver = {
        .name    = "ds18b20",       //可以与dts文件中名字不同
        .owner   = THIS_MODULE,
        .of_match_table = of_match_ptr(ds18b20_of_matches),
    },
    .probe   = ds18b20_probe,
    .remove  = ds18b20_drv_remove,

};


module_platform_driver(ds18b20_driver);

MODULE_LICENSE("GPL");

编译,拷贝,加载模块

这里写图片描述

/************************以下为完全测试*************************/

这里写图片描述
成功获取到温度,有个小bug就是第一获取时温度有问题

以下是完全代码

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#include <linux/of_net.h>
#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>


int ds18_gpio = -1;



#define GPIO_DS18B20    ds18_gpio

#define DS18B20_IO_UP   gpio_set_value(GPIO_DS18B20, 1)
#define DS18B20_IO_DOWN     gpio_set_value(GPIO_DS18B20, 0)

#define DS18B20_OUT     gpio_direction_output(GPIO_DS18B20, 1)
#define DS18B20_IN      gpio_direction_input(GPIO_DS18B20)


static void ds18_write(uint16_t data )
{
    uint8_t i, temp;


    DS18B20_OUT;

    for(i=0; i<8; i++)
    {
        temp = data & 0x01;
        data = data >> 1;

        if(temp)         //写1
        {

            DS18B20_IO_DOWN;
            udelay(6); 
            DS18B20_IO_UP;
            udelay(64); 
        }           
      else
        {
            DS18B20_IO_DOWN;
            udelay(60);
            DS18B20_IO_UP;
            udelay(10);


        }
    }


}

static uint8_t ds18_read(void)   //读位
{

    uint8_t data;

    DS18B20_OUT;

    DS18B20_IO_DOWN;

    udelay(6);

    DS18B20_IO_UP;

    DS18B20_IN;

    udelay(9);


    if(gpio_get_value(GPIO_DS18B20)==1){

        data =1;

    }else{

        data =0;
    }

  udelay(45);


  return data;
}


static uint8_t ds18_reads(void)
  {
   uint8_t i = 0,
           temp = 0,
           mydata = 0;

      for(i=0;i<8;i++)
      {
          temp = ds18_read();
          mydata = mydata | (temp<<i); 

      }

  udelay(2);

  return mydata;

  }


static uint8_t ds18_reset(void)
  {


        DS18B20_OUT;
        DS18B20_IO_DOWN;

        udelay(300);

        udelay(300);

        DS18B20_IO_UP;

        DS18B20_IN;  // 600 us

        udelay(100);

        if (gpio_get_value(GPIO_DS18B20) == 0){

            printk("reset bingo \n");
            return 0;

            }




    printk("reset fail \n");

    return -1;

  }



static long ds18b20_ctl(struct file * file,unsigned int cmd,unsigned long num)
{

    uint8_t tp_msb = 0,
            tp_lsb = 0;


    uint32_t data;


    if(cmd){    //read

        printk("star read \n");


        if (ds18_reset() != 0)goto error1;
        ds18_write(0xCC);
        udelay(1);
        ds18_write(0x44);     //转换温度

        //mdelay(100);
        //ssleep(1);
        if (ds18_reset() != 0)goto error1;
        ds18_write(0xCC);
        udelay(1);
        ds18_write(0xBE);   //读取温度

        tp_lsb=  ds18_reads();
        udelay(1);
        tp_msb=  ds18_reads();

        data = tp_msb<<8;
        data = data | tp_lsb;

        if( data < 0 )      
            data = (~data+1) * 625;    
        else
            data = data * 625;  

        printk("tmp = %d \n", data);



    }

    return 0;

    error1:
        printk("read error \n");
        return -1;

}



struct file_operations ds18b20_fops = {

        .unlocked_ioctl= ds18b20_ctl,

};


struct miscdevice  ds18b20_misc={

        .minor = 200,
        .name = "misc_ds18b20",
        .fops = &ds18b20_fops,

};

static int ds18b20_probe(struct platform_device *pdev)
{

    struct resource *addr_res = NULL;   /* resources found */


    int re = -1;

    printk("probe!!!!!!!!!! \n");


    ds18_gpio = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);


    printk("%d\n", ds18_gpio);

    re = gpio_request(ds18_gpio, "ds18b20");

    if (re != 0) return -1;

    if (ds18_gpio > 0){


        gpio_direction_output(ds18_gpio, 1);


        }


    re = ds18_reset();            //检测是否存在


    if (!re){

        printk("finded ds18b20 \n");

        misc_register(&ds18b20_misc);

        return 0;

    }else{

        gpio_free(GPIO_DS18B20);

        printk("no find ds18b20 \n");

        return -1;
    }





    return 0;
}


static int ds18b20_drv_remove(struct platform_device *pdev)
{

    gpio_free(ds18_gpio);

    return 0;
}


static const struct of_device_id ds18b20_of_matches[] = {
    { .compatible = "ds18b20", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ds18b20_of_matches);



static struct platform_driver ds18b20_driver = {
    .driver = {
        .name    = "ds18b20",
        .owner   = THIS_MODULE,
        .of_match_table = of_match_ptr(ds18b20_of_matches),
    },
    .probe   = ds18b20_probe,
    .remove  = ds18b20_drv_remove,

};


module_platform_driver(ds18b20_driver);

MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/a1171936767/article/details/80917142