当前位置: 首页 > news >正文

5.platfrom平台点亮led

Platform 点亮一个 LED

1. Platform

Platform 是 Linux 为片上外设提供的一种标准驱动模型,其核心思想是将硬件描述与驱动逻辑分离。硬件信息由设备树描述,Linux 根据设备树创建 Platform Device;驱动程序实现 Platform Driver;Platform 总线负责两者的自动匹配,匹配成功后调用 probe() 完成设备初始化。

2. 设备树修改

2.1 在设备树里添加 GPIO 节点

gpioled { #address-cells = <1>; #size-cells = <1>; compatible = "atkalpha,gpioled"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_led>; led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; status = "okay"; };
  1. gpioled
    节点名称(Node Name),表示这里定义了一个叫 gpioled 的设备。
    在开发板上可以查看是否挂载上:
    切换到 device-tree 目录查看:
  2. #address-cells = <1>;
    这个属性表示:如果这个节点下面还有子节点,那么子节点的地址用 1 个 cell 表示。
  3. #size-cells = <1>; 子节点的 size(大小)用 1 个 cell 表示。
  4. compatible = “atkalpha,gpioled”;
    告诉 Linux 我是一个类型为 atkalpha,gpioled 的设备。
  5. pinctrl-names = “default”;
    这个设备有一套默认的引脚配置,default 是这套配置的名字。
  6. pinctrl-0 = <&pinctrl_led>;
    默认使用 pinctrl_led 这组引脚配置,这个配置下方有说明。
  7. led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
    LED 使用 gpio1 控制器的第 3 号引脚。
  8. status = “okay”;
    表示启用这个设备。
    如果写:status = “disabled”;,Linux 会忽略这个节点。

2.2 在设备树中添加 pinctrl 引脚配置节点

pinctrl_led: ledgrp { fsl,pins = < MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0 /* LED0 */ >; };
  1. pinctrl_led:
    这个是节点标签,它的作用是给该节点起一个引用名称,方便其他节点引用。
  2. ledgrp
    这个是节点名称,表示它是给 LED 用的。
  3. MX6UL_PAD_GPIO1_IO03__GPIO1_IO03
    含义是把 i.MX6ULL 的 GPIO1_IO03 这个物理引脚配置为 GPIO1_IO03 功能。
  4. 0x10B0
    引脚电气属性配置值,用于设置驱动能力、速度、上下拉等。

3. 驱动代码

3.1 主体框架

以下为主体框架

static int led_probe(struct platform_device *dev) { } static int led_remove(struct platform_device *dev) { return 0; } struct of_device_id led_of_match[] = { {.compatible = ""}, { /* sentinel */ }, }; struct platform_driver led_driver = { .driver = .probe = .remove = }; /* 驱动加载 */ static int __init leddriver_init(void) { return platform_driver_register(&led_driver); } /* 驱动卸载 */ static void __exit leddriver_exit(void) { platform_driver_unregister(&led_driver); } module_init(leddriver_init); module_exit(leddriver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("huangjiajing");

整体框架主要由以下四部分组成:
Platform 驱动框架

├── probe() 设备匹配成功后执行
├── remove() 驱动卸载或设备移除时执行
├── platform_driver 描述 Platform 驱动
└── 驱动注册与注销
首先是 struct platform_driver led_driver 这个结构体:

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; bool prevent_deferred_probe; };

里面用到 probe、remove 这两个函数,还有 device_driver driver 这个结构体。

  • probe():Platform 驱动的入口函数,负责设备初始化和资源申请。
  • remove():Platform 驱动的退出函数,负责资源释放和设备清理。
  • device_driver driver:用于描述驱动信息(如nameof_match_table),供 Linux 完成设备与驱动的匹配。
    接下来介绍 device_driver 这个结构体:
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };

这里面要用到的是 name 和 of_match_table,用于匹配设备树:

  • name 用于指定驱动名称,在没有使用设备树时,Linux 可以根据设备名和驱动名进行匹配。
  • of_match_table 用于指定设备树匹配表,Linux 根据设备树节点的 compatible 属性与该匹配表进行匹配。匹配成功后会调用 probe()。
    接下来 probe() 和 remove() 的实现逻辑与前一章类似。

3.2 完整代码

#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/string.h> #include <linux/irq.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/interrupt.h> #include <linux/poll.h> #include <linux/fcntl.h> #include <linux/ide.h> #include <linux/platform_device.h> #define GPIOLED_CNT 1 #define GPIOLED_NAME "dtsplatled" #define LEDOFF 0 #define LEDON 1 /* gpioled设备结构体 */ struct gpioled_dev{ dev_t devid; int major; int minor; struct cdev cdev; struct class *class; struct device *device; struct device_node *nd; int led_gpio; }; struct gpioled_dev gpioled; /* LED */ static int led_open(struct inode *inode, struct file *filp) { filp->private_data = &gpioled; return 0; } static int led_release(struct inode *inode, struct file *filp) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { int ret; unsigned char databuf[1]; struct gpioled_dev *dev = filp->private_data; ret = copy_from_user(databuf, buf, count); if(ret < 0) { return -EINVAL; } if(databuf[0] == LEDON) { gpio_set_value(dev->led_gpio, 0); } else if(databuf[0] == LEDOFF) { gpio_set_value(dev->led_gpio, 1); } return 0; } /* 操作集 */ static const struct file_operations led_fops = { .owner = THIS_MODULE, .write = led_write, .open = led_open, .release = led_release, }; static int led_probe(struct platform_device *dev) { ` /* 1,获取设备节点 */ #if 0 gpioled.nd = of_find_node_by_path("/gpioled"); if(gpioled.nd == NULL) { ret = -EINVAL; goto fail_findnode; } #endif gpioled.nd = dev->dev.of_node; /* 2, 获取LED所对应的GPIO */ gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); if(gpioled.led_gpio < 0) { printk("can't find led gpio\r\n"); ret = -EINVAL; goto fail_findnode; } printk("led gpio num = %d\r\n", gpioled.led_gpio); /* 3,申请IO */ ret = gpio_request(gpioled.led_gpio, "led-gpio"); if (ret) { printk("Failed to request the led gpio\r\n"); ret = -EINVAL; goto fail_findnode; } /* 4,使用IO,设置为输出 */ ret = gpio_direction_output(gpioled.led_gpio, 1); if (ret) { goto fail_setoutput; } /* 5,输出底电平,点亮LED灯*/ gpio_set_value(gpioled.led_gpio, 0); return 0; fail_setoutput: gpio_free(gpioled.led_gpio); fail_findnode: return ret; } static int led_remove(struct platform_device *dev) { printk("led remove\r\n"); /* 关灯 */ gpio_set_value(gpioled.led_gpio, 1); /* 注销字符设备驱动 */ cdev_del(&gpioled.cdev); unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); device_destroy(gpioled.class, gpioled.devid); class_destroy(gpioled.class); /* 释放IO */ gpio_free(gpioled.led_gpio); return 0; } struct of_device_id led_of_match[] = { {.compatible = "atkalpha,gpioled"}, { /* sentinel */ }, }; struct platform_driver led_driver = { .driver = { .name = "imx6ull-led", /* 无设备树和设备进行匹配,驱动名字 */ .of_match_table = led_of_match, /* 设备树匹配表 */ }, .probe = led_probe, .remove = led_remove, }; /* 驱动加载 */ static int __init leddriver_init(void) { return platform_driver_register(&led_driver); } /* 驱动卸载 */ static void __exit leddriver_exit(void) { platform_driver_unregister(&led_driver); } module_init(leddriver_init); module_exit(leddriver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("huangjiajing"); static int __init leddriver_init(void) { return platform_driver_register(&led_driver); } /* 驱动卸载 */ static void __exit leddriver_exit(void) { platform_driver_unregister(&led_driver); } module_init(leddriver_init); module_exit(leddriver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("huangjiajing");
http://www.jsqmd.com/news/1151726/

相关文章:

  • 2026 年 GEO 组织能力趋势:企业该配什么团队?怎么转型?
  • 被算力“卡脖”,DeepSeek 70 亿美元豪赌自研 AI 推理芯片,胜算几何?
  • 不爱喝中药味饮品的人,如何选口感温润的木耳菌菇露
  • 从 TLE 到极速通过:Java 算法竞赛大数据量输入优化(BufferedReader + StringTokenizer 详解)
  • Linux talk 命令详解:经典终端实时聊天工具,无需图形界面即可对话
  • GPT-4o 与 Claude 3.5 Sonnet 对比:5种Mermaid图表Prompt生成准确率实测
  • 别盲目复制AI代码!上线前必须做好这8道风控
  • AI 智能体工程实践:从大模型宕机到稳定数学解题
  • “肥料袋定制攻略:盛军塑业如何破解农资包装痛点“
  • 2026年最新发布:高性价比苦荞早餐片优选榜单揭晓
  • 全球首个地层学AI大模型:从手工比对到智能解读地球演化史
  • 二本人工智能专业真的好就业吗?普通二本生 4 条真实出路不画大饼
  • nRF52840极简项目:Zephyr内核API最小化冗余使用指南
  • CTF WriteUp:多层 Base 编码嵌套解密
  • 软件被杀毒软件误报?代码签名证书为什么能消除警告
  • 国内Agent产品和国外比到底差在哪里?从底层架构到工程化落地的深度测评
  • 性价比高的南京净化工程哪个公司好
  • Claude 的 Microsoft 365 connector 能写入了,技术接入别跳过权限验收
  • 基于单片机睡眠质量检测 鼾声检测 心率血氧体温监测无线传输设计13(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • nVisual:以真实资源现状支撑规划,无效/超前投资减少20%
  • 如何用3个步骤彻底解决Windows“此电脑“流氓快捷方式:MyComputerManager终极方案解析
  • 模型路由技术:实现AI任务智能调度与成本优化的核心机制
  • 01-Flutter鸿蒙开发从0开始:认识项目路线和学习顺序
  • 或与异或【牛客tracker 每日一题】
  • 【JAVA毕设源码分享】基于SpringBoot框架的”校联云桥”校友管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • DAB变换器单移相闭环控制Simulink仿真:从100V到400V双向功率流验证
  • Android随笔-PMS
  • 屈臣氏美团闪购优惠怎么领取?分享最近下单时发现的几个活动
  • 从 PHP 到 AI + Golang,程序员自救转型手记(二十六):icon 组件封装
  • 这一战只凭侠义!《墨香情》手游官方下载,丹青水墨复古江湖,无职业零氪畅玩!