目录
三种驱动框架分别为:
①寄存器映射版本
②设备树版本
③pinctrl、gpio子系统版本
应用程序可共用同一个
CPU:NXP的I.MX6ULL,基于ARM Cortex-A7架构;
开发板:正点原子I.MX6U-ALPHA;
linux内核:linux-4.1.15‘;
板子的LED0接到了GPIO3_IO03引脚上,当GPIO3_IO03输出为低电平(0)时二极管导通LED0就会被点亮;当GPIO3_IO03输出为高电平(1)时二极管截止LED0就会熄灭;
(一个小小的建议:初学者一定要养成多动手翻看参考手册和原理图的习惯,这样今后的学习过程更容易举一反三)
<1>使能 GPIO1时钟
将寄存器CCM_CCGR1(物理地址:0x020C406C)的 bit27 和 bit26 这两个位,置成11;
<2>设置 GPIO1_IO03的复用功能为GPIO模式
往寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03中写入0x5即可,对应下图中的ALT5
<3>配置 GPIO1_IO03 的电气属性
往寄存器“IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03"写入0x10B0(前十六位为: 0001 0000 1011 0000);
设置 IO的上下拉、速度等等。
<4>设置GPIO1_IO03作为输出功能
把寄存器 GPIO1_GDIR 的 bit3 置 1 ,表示GPIO作输出
<5>控制GPIO1_IO03输出电平
向 GPIO1_DR寄存器的 bit3 写入0即可控制 GPIO1_IO03输出低电平(开灯),写入1即可控制 GPIO1_IO03输出高电平(熄灯)
- /*
- * @Author: imysy_22
- * @Description: led灯字符型驱动程序寄存器映射版本
- * @Date: 2022-10-17 12:46:27
- * @LastEditTime: 2022-10-17 00:00:09
- * @FilePath: /undefined/home/imysy22/IMX6U/rootfs/home/root/MyDrivers/2_led_chrdev/common_version/led.c
- */
- #include
- #include
- #include
-
- #include
- #include
- #include
- #include
- #include
-
- #define DevName "Mychr_led"
-
- static int DevMajor = 11;
- static int DevMinor = 0;
-
- /* 要点亮一个led灯所要操作的寄存器地址 */
- #define CCM_CCGR1_BASE 0x020C406C
- #define SW_MUX_GPIO1_IO03_BASE 0x020E0068
- #define SW_PAD_GPIO1_IO03_BASE 0x020E02F4
- #define GPIO1_DR_BASE 0x0209C000
- #define GPIO1_GDIR_BASE 0x0209C004
-
- /* 寄存器物理地址映射的虚拟地址 */
- static void __iomem *IMX6U_CCM_CCGR1;
- static void __iomem *SW_MUX_GPIO1_IO03;
- static void __iomem *SW_PAD_GPIO1_IO03;
- static void __iomem *GPIO1_DR;
- static void __iomem *GPIO1_GDIR;
-
- /**
- * @description: 初始化、配置好寄存器
- */
- static void led_ioremap(void)
- {
- unsigned long RegVal = 0;
-
- /* 1、把寄存器的物理地址映射到虚拟地址 */
- IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4); //4代表4个字节,4x8=32位寄存器
- SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
- SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
- GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
- GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
-
- /* 2、开启GPIO1的时钟 */
- RegVal = readl(IMX6U_CCM_CCGR1);
- RegVal &= ~(0x3 << 26);
- RegVal |= (0x3 << 26);
- writel(RegVal, IMX6U_CCM_CCGR1);
-
- /* 3、把GPIO1_IO3复用成gpio */
- writel(0x5, SW_MUX_GPIO1_IO03);
-
- /* 4、设置io属性 */
- writel(0x10B0, SW_PAD_GPIO1_IO03);
-
- /* 5、配置成输出功能 */
- RegVal = readl(GPIO1_GDIR);
- RegVal &= ~(0x1 << 3);
- RegVal |= (0x1 << 3);
- writel(RegVal, GPIO1_GDIR);
-
- /* 6、默认输出高电平,关闭led */
- RegVal = readl(GPIO1_DR);
- RegVal &= ~(0x1 << 3);
- RegVal |= (0x1 << 3);
- writel(RegVal, GPIO1_DR);
- }
-
- static void led_on(void)
- {
- unsigned long RegVal = 0;
-
- RegVal = readl(GPIO1_DR);
- RegVal &= ~(0x1 << 3);
- writel(RegVal, GPIO1_DR);
-
- }
-
- static void led_off(void)
- {
- unsigned long RegVal = 0;
-
- RegVal = readl(GPIO1_DR);
- RegVal |= (0x1 << 3);
- writel(RegVal, GPIO1_DR);
-
- }
-
- struct led_dev {
- struct cdev mdev;
-
- struct class *pcls;
- struct device *pdev;
- };
-
- struct led_dev gmydev;
-
- /**
- * @description:
- * @param {inode} *pnode
- * @param {file} *pfile 设备文件,file结构体有个叫做private_data的成员变量,一般在open的时候将private_data指向设备结构体。
- * @return {*}
- */
- static int chr_led_open(struct inode *pnode,struct file *pfile)
- {
- pfile->private_data = (void *) (container_of(pnode->i_cdev, struct led_dev, mdev)); //设置私有数据,后续可以直接找到gmydev的地址
-
- return 0;
- }
-
- static int chr_led_release(struct inode *pnode,struct file *pfile)
- {
-
- return 0;
- }
-
- static ssize_t chr_led_write(struct file *pfile,const char __user *puser,size_t size,loff_t *p_pos)
- {
- int ret = 0;
- char buf[1] = {0};
- unsigned char led_state;
-
- if((ret = copy_from_user(buf, puser, size)))
- {
- printk("copy_from_user failed...\n");
- return -1;
- }
-
- led_state = buf[0];
-
- if(led_state == 0)
- {
- led_on(); //低电平开灯
- }
-
- if(led_state == 1)
- {
- led_off(); //高电平关灯
- }
-
- return 1;
- }
-
-
- struct file_operations myops = {
- .owner = THIS_MODULE,
- .open = chr_led_open,
- .release = chr_led_release,
- .write = chr_led_write,
- };
-
- static int __init chr_led_init(void)
- {
- int ret = 0;
- dev_t devno = MKDEV(DevMajor, DevMinor);
-
- led_ioremap(); //配置好寄存器
-
- ret = register_chrdev_region(devno, 1, DevName);
- if(ret)
- {
- ret = alloc_chrdev_region(&devno, DevMinor, 1, DevName);
- if(ret)
- {
- printk("register failed...\n");
- return -1;
- }
-
- DevMajor = MAJOR(devno);
- }
-
- cdev_init(&gmydev.mdev, &myops);
-
- gmydev.mdev.owner = THIS_MODULE;
- cdev_add(&gmydev.mdev, devno, 1);
-
- gmydev.pcls = class_create(THIS_MODULE, DevName);
- if(IS_ERR(gmydev.pcls))
- {
- printk("class_create failed...\n");
- cdev_del(&gmydev.mdev);
- unregister_chrdev_region(devno, 1);
-
- return -1;
- }
-
- gmydev.pdev = device_create(gmydev.pcls, NULL, devno, NULL, DevName);
- if(gmydev.pdev == NULL)
- {
- printk("device_create failed...\n");
- class_destroy(gmydev.pcls);
- cdev_del(&gmydev.mdev);
- unregister_chrdev_region(devno, 1);
-
- return -1;
- }
-
- printk("New character device(%d:%d) added successfully.\n", DevMajor, DevMinor);
-
- return 0;
- }
-
- static void __exit chr_led_exit(void)
- {
- dev_t devno = MKDEV(DevMajor, DevMinor);
-
- /* 取消映射 */
- iounmap(IMX6U_CCM_CCGR1);
- iounmap(SW_MUX_GPIO1_IO03);
- iounmap(SW_PAD_GPIO1_IO03);
- iounmap(GPIO1_DR);
- iounmap(GPIO1_GDIR);
-
- device_destroy(gmydev.pcls, devno);
- class_destroy(gmydev.pcls);
-
- cdev_del(&gmydev.mdev);
-
- unregister_chrdev_region(devno, 1);
- }
-
- module_init(chr_led_init);
- module_exit(chr_led_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("imysy_22-2022.10.17");
- /*
- * @Author: imysy_22
- * @Description: led灯字符型驱动程序设备树版本
- * @Date: 2022-10-16 15:37:01
- * @LastEditTime: 2022-10-18 17:31:31
- * @FilePath: /undefined/home/imysy22/IMX6U/rootfs/home/root/MyDrivers/2_led_chrdev/device_tree_version/led.c
- */
-
- #include
- #include
- #include
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define DevName "Mychr_led"
-
- //static int gmydev.major = 13;
- //static int gmydev.minor = 0;
-
- static void __iomem *IMX6U_CCM_CCGR1;
- static void __iomem *SW_MUX_GPIO1_IO03;
- static void __iomem *SW_PAD_GPIO1_IO03;
- static void __iomem *GPIO1_DR;
- static void __iomem *GPIO1_GDIR;
-
- struct led_dev {
- int major;
- int minor;
- dev_t devno;
-
- struct cdev mdev;
-
- struct class *pcls;
- struct device *pdev;
-
- struct device_node *pnd;
- struct property *proper;
- };
-
- struct led_dev gmydev;
-
- /**
- * @description: 初始化、配置好寄存器
- */
- static void led_ioremap(struct led_dev gmydev, u32 *RegData);
- static void led_on(void);
- static void led_off(void);
-
-
- /**
- * @description:
- * @param {inode} *pnode
- * @param {file} *pfile 设备文件,file结构体有个叫做private_data的成员变量,一般在open的时候将private_data指向设备结构体。
- * @return {*}
- */
- static int chr_led_open(struct inode *pnode,struct file *pfile)
- {
- pfile->private_data = (void *) (container_of(pnode->i_cdev, struct led_dev, mdev));
-
- return 0;
- }
-
- static int chr_led_release(struct inode *pnode,struct file *pfile)
- {
-
- return 0;
- }
-
- static ssize_t chr_led_write(struct file *pfile,const char __user *puser,size_t size,loff_t *p_pos)
- {
- int ret = 0;
- char buf[1] = {0};
- unsigned char led_state;
-
- if((ret = copy_from_user(buf, puser, size)))
- {
- printk("copy_from_user failed...\n");
- return -1;
- }
-
- led_state = buf[0];
-
- if(led_state == 0)
- {
- led_on(); //低电平开灯
- }
-
- if(led_state == 1)
- {
- led_off(); //高电平关灯
- }
-
- return 1;
- }
-
-
- struct file_operations myops = {
- .owner = THIS_MODULE,
- .open = chr_led_open,
- .release = chr_led_release,
- .write = chr_led_write,
- };
-
- static int __init chr_led_init(void)
- {
- int ret = 0;
- const char *str;
- u32 RegData[14] = {0};
- unsigned char i = 0;
-
- /* 获取设备树中的属性数据 */
-
- /* 1、获取设备节点:alpha-led */
- if((gmydev.pnd = of_find_node_by_path("/alpha-led")) == NULL)
- {
- printk("of_find_node_by_path failed...\n");
- return -EINVAL;
- }
-
- /* 2、获取compatible属性内容 */
- if((gmydev.proper = of_find_property(gmydev.pnd, "atkalpha-led", NULL)) == NULL)
- {
- printk("of_find_property failed...\n");
- //return -1;
- }
-
- /* 3、获取status属性内容 */
- if((ret = of_property_read_string(gmydev.pnd, "status", &str)) < 0)
- {
- printk("of_property_read_string failed...\n");
- //return -1;
- }
-
- printk("status = %s\n", str);
-
- /* 4、获取reg属性内容 */
-
- if((ret = of_property_read_u32_array(gmydev.pnd, "reg", RegData, 10)) < 0)
- {
- printk("of_property_read_u32_array failed...\n");
- //return -1;
- }
-
-
- printk("reg data :\n");
-
- for(i = 0;i < 10; i++)
- printk("%#x ", RegData[i]);
-
- printk("\n");
-
- /* static void led_ioremap(void)函数 */
- led_ioremap(gmydev, RegData);
-
- gmydev.major = 13;
- gmydev.minor = 0;
- gmydev.devno = MKDEV(gmydev.major, gmydev.minor);
-
- ret = register_chrdev_region(gmydev.devno, 1, DevName);
- if(ret)
- {
- ret = alloc_chrdev_region(&gmydev.devno, gmydev.minor, 1, DevName);
- if(ret)
- {
- printk("register failed...\n");
- return -1;
- }
-
- gmydev.major = MAJOR(gmydev.devno);
- gmydev.minor = MINOR(gmydev.devno);
- }
-
- cdev_init(&gmydev.mdev, &myops);
-
- gmydev.mdev.owner = THIS_MODULE;
- cdev_add(&gmydev.mdev, gmydev.devno, 1);
-
- gmydev.pcls = class_create(THIS_MODULE, DevName);
- if(IS_ERR(gmydev.pcls))
- {
- printk("class_create failed...\n");
- cdev_del(&gmydev.mdev);
- unregister_chrdev_region(gmydev.devno, 1);
-
- return -1;
- }
-
- gmydev.pdev = device_create(gmydev.pcls, NULL, gmydev.devno, NULL, DevName);
- if(gmydev.pdev == NULL)
- {
- printk("device_create failed...\n");
- class_destroy(gmydev.pcls);
- cdev_del(&gmydev.mdev);
- unregister_chrdev_region(gmydev.devno, 1);
-
- return -1;
- }
-
- printk("New character device(%d:%d) added successfully.\n", gmydev.major, gmydev.minor);
-
- return 0;
- }
-
- static void __exit chr_led_exit(void)
- {
- /* 取消映射 */
- iounmap(IMX6U_CCM_CCGR1);
- iounmap(SW_MUX_GPIO1_IO03);
- iounmap(SW_PAD_GPIO1_IO03);
- iounmap(GPIO1_DR);
- iounmap(GPIO1_GDIR);
-
- device_destroy(gmydev.pcls, gmydev.devno);
- class_destroy(gmydev.pcls);
-
- cdev_del(&gmydev.mdev);
-
- unregister_chrdev_region(gmydev.devno, 1);
- }
-
- static void led_ioremap(struct led_dev gmydev, u32 *RegData)
- {
- unsigned long RegVal = 0;
-
- /* 1、把寄存器的物理地址映射到虚拟地址 */
- #if 1
- IMX6U_CCM_CCGR1 = ioremap(RegData[0], RegData[1]); //4代表4个字节,4x8=32位寄存器
- SW_MUX_GPIO1_IO03 = ioremap(RegData[2], RegData[3]);
- SW_PAD_GPIO1_IO03 = ioremap(RegData[4], RegData[5]);
- GPIO1_DR = ioremap(RegData[6], RegData[7]);
- GPIO1_GDIR = ioremap(RegData[8], RegData[9]);
- #else
- IMX6U_CCM_CCGR1 = of_ioremap(RegData[0], RegData[1]); //4代表4个字节,4x8=32位寄存器
- SW_MUX_GPIO1_IO03 = of_ioremap(RegData[2], RegData[3]);
- SW_PAD_GPIO1_IO03 = of_ioremap(RegData[4], RegData[5]);
- GPIO1_DR = of_ioremap(RegData[6], RegData[7]);
- GPIO1_GDIR = of_ioremap(RegData[8], RegData[9]);
- #endif
- /* 2、开启GPIO1的时钟 */
- RegVal = readl(IMX6U_CCM_CCGR1);
- RegVal &= ~(0x3 << 26);
- RegVal |= (0x3 << 26);
- writel(RegVal, IMX6U_CCM_CCGR1);
-
- /* 3、把GPIO1_IO3复用成gpio */
- writel(0x5, SW_MUX_GPIO1_IO03);
-
- /* 4、设置io属性 */
- writel(0x10B0, SW_PAD_GPIO1_IO03);
-
- /* 5、配置成输出功能 */
- RegVal = readl(GPIO1_GDIR);
- RegVal &= ~(0x1 << 3);
- RegVal |= (0x1 << 3);
- writel(RegVal, GPIO1_GDIR);
-
- /* 6、默认输出高电平,关闭led */
- RegVal = readl(GPIO1_DR);
- RegVal &= ~(0x1 << 3);
- RegVal |= (0x1 << 3);
- writel(RegVal, GPIO1_DR);
- }
-
- static void led_on(void)
- {
- unsigned long RegVal = 0;
-
- RegVal = readl(GPIO1_DR);
- RegVal &= ~(0x1 << 3);
- writel(RegVal, GPIO1_DR);
-
- }
-
- static void led_off(void)
- {
- unsigned long RegVal = 0;
-
- RegVal = readl(GPIO1_DR);
- RegVal |= (0x1 << 3);
- writel(RegVal, GPIO1_DR);
-
- }
-
- module_init(chr_led_init);
- module_exit(chr_led_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("imysy_22-2022.10.16");
需要在 “ / ” 根节点下增加一个“alpha-led”子节点
- alpha-led { /* LED第一代:《设备树版》 */
- #address-cells = <1>; /* 用于描述子节点的地址信息,即reg属性中,地址信息占几个uint32 */
- #size-cells = <1>; /* 地址长度占几个u32,单位为u32(4字节) */
- compatible = "atkalpha-led";
- status = "okey";
- reg = < 0X020C406C 0X04 /* CCM_CCGR1_BASE */
- 0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
- 0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
- 0X0209C000 0X04 /* GPIO1_DR_BASE */
- 0X0209C004 0X04 /* GPIO1_GDIR_BASE */
- >;
- };
- /*
- * @Author: imysy_22
- * @Description: led灯字符型驱动程序pinctrl_gpio子系统版本
- * @Date: 2022-10-18 23:12:03
- * @LastEditTime: 2022-10-18 23:48:27
- * @FilePath: /undefined/home/imysy22/IMX6U/Linux_Drivers/2_led_chrdev/pinctrl_gpio_version/led.c
- */
-
- #include
- #include
- #include
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define DevName "gpioled"
-
- struct gpioled_dev {
- int major;
- int minor;
- int led_gpio; /* led所使用的gpio编号 */
- dev_t devno;
-
- struct cdev mdev;
-
- struct class *pcls;
- struct device *pdev;
-
- struct device_node *pnd;
- struct property *proper;
-
- };
-
- struct gpioled_dev gmydev;
-
- static void led_on(struct file *pfile);
- static void led_off(struct file *pfile);
-
- /**
- * @description:
- * @param {inode} *pnode
- * @param {file} *pfile 设备文件,file结构体有个叫做private_data的成员变量,一般在open的时候将private_data指向设备结构体。
- * @return {*}
- */
- static int chr_led_open(struct inode *pnode,struct file *pfile)
- {
- pfile->private_data = (void *) (container_of(pnode->i_cdev, struct gpioled_dev, mdev));
-
- return 0;
- }
-
- static int chr_led_release(struct inode *pnode,struct file *pfile)
- {
-
- return 0;
- }
-
- static ssize_t chr_led_write(struct file *pfile,const char __user *puser,size_t size,loff_t *p_pos)
- {
- int ret = 0;
- char buf[1] = {0};
- unsigned char led_state;
-
- if((ret = copy_from_user(buf, puser, size)))
- {
- printk("copy_from_user failed...\n");
- return -1;
- }
-
- led_state = buf[0];
-
- if(led_state == 0)
- {
- led_on(pfile); //低电平开灯
- }
-
- if(led_state == 1)
- {
- led_off(pfile); //高电平关灯
- }
-
- return 1;
- }
-
-
- struct file_operations myops = {
- .owner = THIS_MODULE,
- .open = chr_led_open,
- .release = chr_led_release,
- .write = chr_led_write,
- };
-
- static int __init chr_led_init(void)
- {
- int ret = 0;
-
- /*
- 获取设备树中的属性数据
- 前面操作设备树节点这几步操作和设备树版本的不一样
- */
-
- /* 1、获取设备节点:gpioled */
- if((gmydev.pnd = of_find_node_by_path("/gpioled")) == NULL)
- {
- printk("of_find_node_by_path failed...\n");
- return -EINVAL;
- }
-
- /* 2、获取gpio子系统中设备树中的gpio的电气属性,并得到Led所使用的GPIO编号 */
- if((gmydev.led_gpio = of_get_named_gpio(gmydev.pnd, "led-gpio", 0)) < 0)
- {
- printk("of_get_named_gpio failed...\n");
- return -EINVAL;
- }
-
- printk("led-gpio num = %d\n", gmydev.led_gpio);
-
- /* 3、设置GPIO1_IO03为输出,并输出高电平,默认熄灭led灯 */
- if((ret = gpio_direction_output(gmydev.led_gpio, 1)) < 0)
- {
- printk("gpio_direction_output failed...\n");
- return -EINVAL;
- }
-
- printk("**LED0 initialzation successed***\n");
-
- /* 注册设备流程和设备树版本的LED一样 */
-
- gmydev.major = 14;
- gmydev.minor = 0;
- gmydev.devno = MKDEV(gmydev.major, gmydev.minor);
-
- ret = register_chrdev_region(gmydev.devno, 1, DevName);
- if(ret)
- {
- ret = alloc_chrdev_region(&gmydev.devno, gmydev.minor, 1, DevName);
- if(ret)
- {
- printk("register failed...\n");
- return -1;
- }
-
- gmydev.major = MAJOR(gmydev.devno);
- gmydev.minor = MINOR(gmydev.devno);
- }
-
- cdev_init(&gmydev.mdev, &myops);
-
- gmydev.mdev.owner = THIS_MODULE;
- cdev_add(&gmydev.mdev, gmydev.devno, 1);
-
- gmydev.pcls = class_create(THIS_MODULE, DevName);
- if(IS_ERR(gmydev.pcls))
- {
- printk("class_create failed...\n");
- cdev_del(&gmydev.mdev);
- unregister_chrdev_region(gmydev.devno, 1);
-
- return -1;
- }
-
- gmydev.pdev = device_create(gmydev.pcls, NULL, gmydev.devno, NULL, DevName);
- if(gmydev.pdev == NULL)
- {
- printk("device_create failed...\n");
- class_destroy(gmydev.pcls);
- cdev_del(&gmydev.mdev);
- unregister_chrdev_region(gmydev.devno, 1);
-
- return -1;
- }
-
- printk("New character device(%d:%d) added successfully.\n", gmydev.major, gmydev.minor);
-
- return 0;
- }
-
- static void __exit chr_led_exit(void)
- {
- device_destroy(gmydev.pcls, gmydev.devno);
- class_destroy(gmydev.pcls);
-
- cdev_del(&gmydev.mdev);
-
- unregister_chrdev_region(gmydev.devno, 1);
- }
-
- static void led_on(struct file *pfile)
- {
- struct gpioled_dev *pmydev = pfile->private_data;
-
- gpio_set_value(pmydev->led_gpio, 0);
-
- }
-
- static void led_off(struct file *pfile)
- {
- struct gpioled_dev *pmydev = pfile->private_data;
-
- gpio_set_value(pmydev->led_gpio, 1);
- }
-
- module_init(chr_led_init);
- module_exit(chr_led_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("imysy_22-2022.10.16");
在" / "根节点外部的 iomuxc 节点的“imx6ul-evk”子节点下创建一个名为“pinctrl_led”子子节点(套娃)
- pinctrl_led: ledgrp { /* LED第二代:《pinctrl和gpio子系统版》 */
- fsl,pins = <
- MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0
- >;
- };
其中,MX6UL_PAD_GPIO1_IO03__GPIO1_IO03这个宏的定义在文件arch/arm/boot/dts/imx6ul-pinfunc.h中。
再在" / "根节点内部创建一个“gpioled”节点
- 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 = "okey";
- };
添加完后,一定不要忘记检查PIN是否正被其他外设使用!!!
在设备树中搜索“ GPIO1_IO03 ”,如果有别的设备节点在也在使用这个PIN的话,屏蔽它
pinctrl_tsc节点是TSC(电阻触摸屏接口)的pinctrl节点,从第480行可以看出,默认情况下GPIO1_IO03作为了TSC外设的PIN。所以我们需要将第480行屏蔽掉!和C语言一样,在要屏蔽的内容前后加上“/*”和“*/”符号即可。实际上我们目前并不会用到这个节点,所以我干脆把它的PIN全屏蔽了。
编译设备树
进入Linux顶层源码目录,生成imx6ull-alientek-emmc.dts并重启开发板时加载这个新的设备树
正确的现象:/proc/device-tree目录下生成了我们的“ gpioled ”文件,进入文件后会自动生成我们之前在设备树里 “gpioled” 节点中的'#address-cells' compatible led-gpio name pinctrl-0 pinctrl-names '#size-cells' status属性
第32行的open函数需根据不同的驱动程序申请的字符设备名字不同进行修改
- /*
- * @Author: imysy_22
- * @Description: 三个字符驱动版本都统用的LED点灯应用程序
- * @Date: 2022-10-17 12:46:27
- * @LastEditTime: 2022-10-17 14:15:19
- * @FilePath: /undefined/home/imysy22/IMX6U/Linux_Drivers/2_led_chrdev/common_version/App.c
- */
-
- #include
- #include
- #include
- #include
- #include
- #include
-
- int main(int argc, const char *argv[])
- {
- int fd = -1;
- int ret;
- unsigned char led_state[1];
-
- /* 低电平点灯,高电平熄灭 */
- if(argc != 2)
- {
- printf("*********************************************\n");
- printf("* Please input : ./App 0-led_on / 1-led_off *\n");
- printf("*********************************************\n");
-
- return -1;
- }
-
- if((fd = open("/dev/Mychr_led", O_WRONLY)) < 0)
- {
- perror("open");
- return -1;
- }
-
- printf("***open success***\n\n\n");
-
- led_state[0] = atoi(argv[1]);
-
- /* 如果是点灯 */
- if(led_state[0] == 0)
- {
- if((ret = write(fd, led_state, 1)) < 0)
- {
- perror("write");
- }
-
- printf("Led is ON!\n");
- }
- else if(led_state[0] == 1)
- {
- if((ret = write(fd, led_state, 1)) < 0)
- {
- perror("write");
- }
-
- printf("Led is OFF!\n");
- }
- else
- {
- printf("You can only input 0 or 1!\n");
- close(fd);
- return -1;
- }
-
- close(fd);
-
- return 0;
- }
-
- CONFIG_MODULE_SIG=n #加了这一行就不会报错:signature and/or required key missing - tainting kernel
- ifeq ($(KERNELRELEASE),)
-
- ifeq ($(ARCH),arm)
- KERNELDIR ?= /home/imysy22/IMX6U/linux-imx-rel_imx_4.1.15_2.1.0_ga
- CC = /home/imysy22/LicheePi/buildroot-2017.08.1/output/host/bin/arm-linux-gnueabihf-gcc
- else
- KERNELDIR ?= /lib/modules/$(shell uname -r)/build
- endif
- PWD := $(shell pwd)
-
- modules:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- modules_install:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install
- clean:
- rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
-
- else
-
- obj-m += led.o
-
- endif
三个模块的实验现象都差不多,只不过insmod led.ko后printk打印的内容不一样而已
# ./App 0 //低电平点亮
# ./App 1 //高电平熄灭
☆ * . ☆
. ∧_∧ ∩ * ☆
* ☆ ( `∀‘)/ .
. ⊂ ノ* ☆
☆ * (つ ノ .☆
(ノ
哈哈用超级复杂的方法点亮led灯,虽然这个实验现象非常low,但是用三种不同的驱动框架来点灯还是着实学不到了不少啊!!!