Linux学习笔记(15.4)——LED设备驱动之面向对象演进4(用设备树)
2022/1/3 7:13:43
本文主要是介绍Linux学习笔记(15.4)——LED设备驱动之面向对象演进4(用设备树),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Linux学习笔记(15.3)采用platform_device指定LED资源,即:
- 首先,根据实际电路将LED的引脚信息(默认状态、打开时电平、GPIO时钟开关位偏移量、引脚序号、GPIO物理地址)初始化;
- 然后,定义struct resource类型的led_res资源,将.start成员指向上面定义的LED引脚信息;
- 接着,定义struct platform_device类型的led_dev资源,指定资源的名称.name、.num_resources(几个LED)、.resource(led_res)成员;
- 最后,在led_dev的初始化函数中将struct platform_device类型的led_dev资源注册到平台设备,即platform_device_register(&led_dev)。
那么,能否省去这个文件不要让具体板子资源挤占linux内核?设备树便应运而生。
- 本文,我们将实际电路的LED信息放在设备树的根节点(如下),内核启动时便将具有compatible属性的gled@0和gled@1节点都转换为平台设备platform_device,当平台驱动platform_driver伴随着设备驱动模块加载时与platform_device匹配。
#define OFF 'C' #define ON 'O' #define LOW 0 #define HIGH 1 gled@0 { compatible = "glen,led_drv"; led_pin = < OFF LOW 26 3 0x020C406C 0x020E0068 0x020E02F4 0x0209C000 0x0209C004 >; }; gled@1 { compatible = "glen,led_drv"; led_pin = < ON LOW 30 1 0x020C406C 0x0229000C 0x02290050 0x020AC000 0x020AC004 >; };
- 稍微修改imx6_gpio_drv.c文件
/** * @file imx6_gpio_drv.c * @author glen (glen_cao@126.com) * @brief * @version 0.1 * @date 2021-12-24 * * @copyright Copyright (c) 2021 * */ #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/device.h> #include <linux/platform_device.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> #include "led_dev.h" static struct gled_device gled[16]; static void imx6_gled_ctrl(u8 idx, u8 status); static int imx6_gled_init(u8 idx); static int imx6_gled_exit(u8 idx); static struct led_ops imx6_gpio_led_ops = { .num = 0, .led_init = imx6_gled_init, .led_exit = imx6_gled_exit, .led_ctrl = imx6_gled_ctrl, }; /** * @brief : 打开/关闭LED * @par : status LEDON('O') 打开LED, LEDOFF('C') 关闭LED * @retval : 无 */ static void imx6_gled_ctrl(u8 idx, u8 status) { u32 val = 0; if (gled[idx].vir_io.ccgr == NULL) return; if (status == ON) { val = readl(gled[idx].vir_io.dr); if (gled[idx].on_level == HIGH) { val |= (1 << (gled[idx].pin)); } else if (gled[idx].on_level == LOW) { val &= ~(1 << gled[idx].pin); } writel(val, gled[idx].vir_io.dr); printk("The led%d is openned!\r\n", idx); } else if (status == OFF) { val = readl(gled[idx].vir_io.dr); if (gled[idx].on_level == HIGH) { val &= ~(1 << gled[idx].pin); } else if (gled[idx].on_level == LOW) { val |= (1 << (gled[idx].pin)); } writel(val, gled[idx].vir_io.dr); printk("The led%d is closed!\r\n", idx); } else { printk("Recived parameter is error!\r\n"); } } /** * @brief LED状态初始化 * @param idx LED */ static int imx6_gled_init(u8 idx) { u32 val; if (idx >= imx6_gpio_led_ops.num) { return -EIO; } /* 寄存器地址映射 */ gled[idx].vir_io.ccgr = ioremap(gled[idx].phy_io.ccgr , 4); gled[idx].vir_io.sw_mux = ioremap(gled[idx].phy_io.sw_mux, 4); gled[idx].vir_io.sw_pad = ioremap(gled[idx].phy_io.sw_pad, 4); gled[idx].vir_io.dr = ioremap(gled[idx].phy_io.dr , 4); gled[idx].vir_io.dir = ioremap(gled[idx].phy_io.dir , 4); /* 使能GPIO时钟 */ val = readl(gled[idx].vir_io.ccgr); val |= (3 << gled[idx].clk_shft_bits); writel(val, gled[idx].vir_io.ccgr); /* 设置gpio1_io03的复用功能 */ writel(5, gled[idx].vir_io.sw_mux); /* 寄存器sw_mux1_io03设置IO属性 */ writel(0x10B0, gled[idx].vir_io.sw_pad); /* 设置gpio1_gdir为输出功能 */ val = readl(gled[idx].vir_io.dir); val |= (1 << gled[idx].pin); writel(val, gled[idx].vir_io.dir); /* 设置led为默认状态 */ val = readl(gled[idx].vir_io.dr); if (gled[idx].dft_status == ON) { if (gled[idx].on_level == HIGH) { val |= (1 << gled[idx].pin); } else if (gled[idx].on_level == LOW) { val &= ~(1 << gled[idx].pin); } } else if (gled[idx].dft_status == OFF) { if (gled[idx].on_level == HIGH) { val &= ~(1 << gled[idx].pin); } else if (gled[idx].on_level == LOW) { val |= (1 << gled[idx].pin); } } writel(val, gled[idx].vir_io.dr); return 0; } /** * @brief LED状态解初始化 * @param idx LED */ static int imx6_gled_exit(u8 idx) { if (idx >= imx6_gpio_led_ops.num) { return -EIO; } iounmap(gled[idx].vir_io.ccgr); iounmap(gled[idx].vir_io.sw_mux); iounmap(gled[idx].vir_io.sw_pad); iounmap(gled[idx].vir_io.dr); iounmap(gled[idx].vir_io.dir); return 0; } /** * @brief */ static int imx6_gpio_probe(struct platform_device *pdev) { u8 i = 0; int ret; struct device_node *nd = pdev->dev.of_node; if (!nd) return -1; i = imx6_gpio_led_ops.num; ret = of_property_read_u32_array(nd, "led_pin", (u32 *)&gled[i], 9); if (ret < 0) printk("Read property \"led_pin\" failed!\r\n"); else { printk("led_pin data:"); for (ret = 0; ret < 9; ret++) { printk("%#X\t", ((u32 *)&(gled[i]))[ret]); } printk("\r\n"); } /* 创建设备节点 */ led_device_create(i); imx6_gpio_led_ops.num++; return 0; } static int imx6_gpio_remove(struct platform_device *pdev) { u8 i; /* 销毁设备节点 */ for (i = 0; i < imx6_gpio_led_ops.num; i++) { led_device_destroy(i); } imx6_gpio_led_ops.num = 0; return 0; } static const struct of_device_id gled_devs[] = { {.compatible = "glen,led_drv"}, { }, }; static struct platform_driver imx6_gpio_driver = { .driver = { .name = "gled", .of_match_table = gled_devs, }, .probe = imx6_gpio_probe, .remove = imx6_gpio_remove, }; static int __init imx6_gpio_drv_init(void) { int ret; ret = platform_driver_register(&imx6_gpio_driver); if (ret) pr_err("Unable to initialize imx6 gpio driver\n"); else pr_info("The imx6 gpio driver is registered.\n"); led_ops_register(&imx6_gpio_led_ops); return ret; } static void __exit imx6_gpio_drv_exit(void) { platform_driver_unregister(&imx6_gpio_driver); } module_init(imx6_gpio_drv_init); module_exit(imx6_gpio_drv_exit); /* insert license for module */ MODULE_LICENSE("GPL"); /* insert author information for module */ MODULE_AUTHOR("glen");
- led_drv.c文件不作修改
- Makefile文件删除atk_board_led.o文件
KERNELDIR := /home/glen/linux/imx6ull/linux/glen_linux CURRENT_PATH := $(shell pwd) #led_driver-y := led_drv.o led_dev.o obj-m += led_drv.o imx6_gpio_drv.o build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
- 测试程序不做更改,验证参考Linux学习笔记(15)——LED设备驱动
这篇关于Linux学习笔记(15.4)——LED设备驱动之面向对象演进4(用设备树)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南
- 2024-08-21【Linux】分区向左扩容的方法