• 驱动开发 platfrom总线驱动的三种方式


    驱动的分隔与分离:

            对于 Linux 这样一个成熟、庞大、复杂的操作系统,代码的重用性非常重要,在驱动程序,因为驱动程序占用了 Linux 内核代码量的大头,如果不对驱动程序加以管理,任由重复的代码肆意增加,那么用不了多久 Linux 内核的文件数量就庞大到无法接受的地步。

            例如:现在有三个SOC A、B 和 C上都有 MPU6050 这个 I2C 接口的六轴传感器,按照我们写裸机 I2C 驱动的时候的思路,每个平台都有一个MPU6050的驱动,那么设备端的驱动将会重复的编写好几次。显然在 Linux 驱动程序中这种写法是不推荐的,最好的做法就是每个SOC的 I2C 控制器都提供一个统一的接口 (也叫做主机驱动),每个设备的话也只提供一个驱动程序(设备驱动),每个设备通过统一的 I2C 接口驱动来访问,这样就可以大大简化驱动文件。

            

            当我们向系统注册一个驱动的时候,总线就会在右侧的设备中查找,看看有没有与之匹配
    的设备,如果有的话就将两者联系起来。同样的,当向系统中注册一个设备的时候,总线就会
    在左侧的驱动中查找看有没有与之匹配的设备,有的话也联系起来。
            在linux内核中的驱动程序都采用总线、驱动和设备这样的模式。
            platform 驱动就是这一思想下的产物。

    总线驱动模型:

            platform总线遵从总线模型,platform是linux内阁抽象出来的软件代码,没有真实的总线和它对应(不存在)

            platfor总线去驱动的思想:是将设备信息和驱动进行分离。platform_device和platform_driver通过总线进行匹配,匹配成功后会执行驱动中的probe函数,在probe函数中可以获取到device中的硬件设备信息。

    以下是platfrom的三种匹配方式:

    一:设备名

    pdrv:

    1. #include<linux/init.h>
    2. #include<linux/module.h>
    3. #include<linux/platform_device.h>
    4. #include<linux/mod_devicetable.h>
    5. struct resource *res;
    6. int irqno;
    7. int pdrv_probe(struct platform_device *pdev)
    8. {
    9. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
    10. if(res==NULL)
    11. {
    12. return ENODATA;
    13. }
    14. irqno=platform_get_irq(pdev,0);
    15. if(irqno<0)
    16. {
    17. return ENODATA;
    18. }
    19. printk("addr:%#llx,irqno:%d\n",res->start,irqno);
    20. return 0;
    21. }
    22. int pdrv_remove(struct platform_device *pdev)
    23. {
    24. printk("%s:%d\n",__func__,__LINE__);
    25. return 0;
    26. }
    27. struct platform_driver pdrv={
    28. .probe=pdrv_probe,
    29. .remove=pdrv_remove,
    30. .driver={
    31. .name="aaaaa",
    32. },
    33. };
    34. module_platform_driver(pdrv);
    35. MODULE_LICENSE("GPL");

    pdev:

    1. #include<linux/init.h>
    2. #include<linux/module.h>
    3. #include<linux/platform_device.h>
    4. struct resource res[]={
    5. [0]={
    6. .start=0x12345678,
    7. .end=0x12345678+49,
    8. .flags=IORESOURCE_MEM,
    9. },
    10. [1]={
    11. .start=71,
    12. .end=71,
    13. .flags=IORESOURCE_IRQ,
    14. },
    15. };
    16. void pdev_release(struct device *dev)
    17. {
    18. printk("%s:%d\n",__func__,__LINE__);
    19. }
    20. struct platform_device pdev=
    21. {
    22. .name="aaaaa",
    23. .id=PLATFORM_DEVID_AUTO,
    24. .dev={
    25. .release=pdev_release,
    26. },
    27. .resource=res,
    28. .num_resources=ARRAY_SIZE(res),
    29. };
    30. static int __init demo_init(void)
    31. {
    32. platform_device_register(&pdev);
    33. return 0;
    34. }
    35. static void __exit demo_exit(void)
    36. {
    37. platform_device_unregister(&pdev);
    38. }
    39. module_init(demo_init);
    40. module_exit(demo_exit);
    41. MODULE_LICENSE("GPL");

     

    二:设备名列表

    pdev:

    1. #include<linux/init.h>
    2. #include<linux/module.h>
    3. #include<linux/platform_device.h>
    4. struct resource res[]={
    5. [0]={
    6. .start=0x12345678,
    7. .end=0x12345678+49,
    8. .flags=IORESOURCE_MEM,
    9. },
    10. [1]={
    11. .start=71,
    12. .end=71,
    13. .flags=IORESOURCE_IRQ,
    14. },
    15. };
    16. void pdev_release(struct device *dev)
    17. {
    18. printk("%s:%d\n",__func__,__LINE__);
    19. }
    20. struct platform_device pdev=
    21. {
    22. .name="hello1",
    23. .id=PLATFORM_DEVID_AUTO,
    24. .dev={
    25. .release=pdev_release,
    26. },
    27. .resource=res,
    28. .num_resources=ARRAY_SIZE(res),
    29. };
    30. static int __init demo_init(void)
    31. {
    32. platform_device_register(&pdev);
    33. return 0;
    34. }
    35. static void __exit demo_exit(void)
    36. {
    37. platform_device_unregister(&pdev);
    38. }
    39. module_init(demo_init);
    40. module_exit(demo_exit);
    41. MODULE_LICENSE("GPL");

    pdrv2:

    1. #include<linux/init.h>
    2. #include<linux/module.h>
    3. #include<linux/platform_device.h>
    4. #include<linux/mod_devicetable.h>
    5. struct resource *res;
    6. int irqno;
    7. int pdrv_probe(struct platform_device *pdev)
    8. {
    9. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
    10. if(res==NULL)
    11. {
    12. return ENODATA;
    13. }
    14. irqno=platform_get_irq(pdev,0);
    15. if(irqno<0)
    16. {
    17. return ENODATA;
    18. }
    19. printk("addr:%#llx,irqno:%d\n",res->start,irqno);
    20. return 0;
    21. }
    22. int pdrv_remove(struct platform_device *pdev)
    23. {
    24. printk("%s:%d\n",__func__,__LINE__);
    25. return 0;
    26. }
    27. struct platform_device_id idtable[]={
    28. {"hello1",0},
    29. {"hello2",1},
    30. {"hello3",2},
    31. {}
    32. };
    33. struct platform_driver pdrv={
    34. .probe=pdrv_probe,
    35. .remove=pdrv_remove,
    36. .driver={
    37. .name="aaaaa",
    38. },
    39. .id_table=idtable,
    40. };
    41. MODULE_DEVICE_TABLE(platform,idtable);
    42. module_platform_driver(pdrv);
    43. MODULE_LICENSE("GPL");

     

    三:设备树

    添加设备树节点:

    pdrv3:

    1. #include<linux/init.h>
    2. #include<linux/module.h>
    3. #include<linux/platform_device.h>
    4. #include<linux/mod_devicetable.h>
    5. #include<linux/of.h>
    6. #include<linux/of_gpio.h>
    7. struct resource *res;
    8. int irqno;
    9. struct gpio_desc *gpiono;
    10. int pdrv_probe(struct platform_device *pdev)
    11. {
    12. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
    13. if(res==NULL)
    14. {
    15. return ENODATA;
    16. }
    17. irqno=platform_get_irq(pdev,0);
    18. if(irqno<0)
    19. {
    20. return ENODATA;
    21. }
    22. printk("addr:%#x,irqno:%d\n",res->start,irqno);
    23. gpiono=gpiod_get_from_of_node(pdev->dev.of_node,"myled1",0,GPIOD_OUT_HIGH,0);
    24. if(IS_ERR(gpiono))
    25. {
    26. printk("获取gpio编号失败\n");
    27. return PTR_ERR(gpiono);
    28. }
    29. gpiod_set_value(gpiono,1);
    30. return 0;
    31. }
    32. int pdrv_remove(struct platform_device *pdev)
    33. {
    34. gpiod_set_value(gpiono,0);
    35. gpiod_put(gpiono);
    36. printk("%s:%d\n",__func__,__LINE__);
    37. return 0;
    38. }
    39. struct of_device_id oftable[]={
    40. {.compatible="hqyj,platform",},
    41. {}
    42. };
    43. struct platform_driver pdrv={
    44. .probe=pdrv_probe,
    45. .remove=pdrv_remove,
    46. .driver={
    47. .name="aaaaa",
    48. .of_match_table=oftable,
    49. },
    50. };
    51. module_platform_driver(pdrv);
    52. MODULE_LICENSE("GPL");

     

     

     

  • 相关阅读:
    数据结构--栈的实现
    【QCustomPlot】下载
    Tailwindcss Layout布局相关样式及实战案例,5万字长文,附完整源码和效果截图
    Docker常见面试题集锦
    501. 二叉搜索树中的众数
    docker中安装并启动rabbitMQ
    wxPython 之 wxAuiManage实现停靠(悬停)子窗口
    OceanBase存储层代码解读(四):宏块的垃圾回收和坏块检查
    uniapp+vue3+ts+vite+echarts开发图表类小程序,将echarts导入项目使用的详细步骤,耗时一天终于弄好了
    Unity_建造系统及保存加载
  • 原文地址:https://blog.csdn.net/brightmante/article/details/128103920