700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【Linux驱动开发】 imx6ull上led驱动程序

【Linux驱动开发】 imx6ull上led驱动程序

时间:2023-04-19 15:46:10

相关推荐

【Linux驱动开发】 imx6ull上led驱动程序

文章目录

数据流向设备树更改pinctrl子系统gpio子系统 驱动编写led_init(void)led_exit(void)设置file_operations,绑定操作

数据流向

用户空间打开设备。

通过 inode 里的设备号在内核中找到cdev。

cdev与一个file_operation绑定。

将该fop 返回给每个进程空间打开的file表,填充一个file 绑定操作,并返回其索引。

设备树更改

设备树主要记录开发板上的设备节点信息。这里先添加自己的节点信息,并把之前使用gpio4_io16的设备状态设为disabled。

leds {compatible = "gpio-leds";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_leds>;status = "default";sysled {lable = "sysled";gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;linux,default-trigger = "heartbeat";default-state = "off";};};my_leds {compatible = "my-leds";status = "okay";pinctrl-names = "default";pinctrl-0 = <&pinctrl_my_leds>;led0{gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;default-state = "off";};led1{gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;default-state = "off";};};

之后在&iomuxc 节点下添加gpio控制的节点

pinctrl_my_leds: my-leds{fsl,pins = <MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x17059 /* my_led */MX6UL_PAD_NAND_DQS__GPIO4_IO16 0x17059 /*board led*/>};

其中 用到了 pinctrl 和 gpio子系统

pinctrl子系统

有三个功能:

获取设备树中pin信息根据获取到的pin信息来设置其复用功能设置其电气特性操作

​ 主要用于简化pin (pad)的电气特性设置操作,上面 0x17059就是对管脚的电气特性进行初始化,电气特性包括:上下拉,速度,驱动能力等。

​ MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09等定义于 imx6ull.dtsi->imx6ull-pinfunc.h->imx6ul-pinfunc.h 文件中。

gpio子系统

初始化gpio并提供相应的gpio控制API,方便开发者使用gpio。

gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;

​ 有3个参数 第一个参数表示 该gpio 属于的chip ,第二个参数表示其属于该chip的第多少号 ,第三个表示其高电平有效。

​ 其中gpio5节点定义于imx6ul.dtsi

驱动编写

首先定义一些变量,结构体,然后模块init函数

定义的结构体

struct gpioled_dev{dev_t devid;/* 设备号 */struct cdev cdev;/* cdev */struct class *class;/* 类 */struct device *device;/* 设备 */int major;/* 主设备号 */int minor;/* 次设备号 */struct device_node*nd; /* 设备节点 */int led_gpio;/* sysled所使用的GPIO编号*/int led1_gpio; /* 外接的led gpio编号 */};

led_init(void)

static int __init led_init(void){int ret = 0;const char *str;/* 设置LED所使用的GPIO *//* 1、获取设备节点:gpioled */gpioled.nd = of_find_node_by_path("/my_leds");if(gpioled.nd == NULL) {printk("gpioled node not find!\r\n");return -EINVAL;}/* 2.读取status属性 */ret = of_property_read_string(gpioled.nd, "status", &str);if(ret < 0) return -EINVAL;if (strcmp(str, "okay"))return -EINVAL;/* 3、获取compatible属性值并进行匹配 */ret = of_property_read_string(gpioled.nd, "compatible", &str);if(ret < 0) {printk("gpioled: Failed to get compatible property\n");return -EINVAL;}if (strcmp(str, "my-leds")) {printk("gpioled: Compatible match failed %s\n",str);return -EINVAL;}/* 4、 获取设备树中的gpio属性,得到LED所使用的LED编号 */gpioled.led_gpio = of_get_named_gpio(of_find_node_by_path("/my_leds/led1"), "gpios", 0);if(gpioled.led_gpio < 0) {printk("can't get sysled gpios");return -EINVAL;}gpioled.led1_gpio = of_get_named_gpio(of_find_node_by_path("/my_leds/led0"), "gpios", 0);if (gpioled.led1_gpio < 0){printk("can't get led1 gpios");return -EINVAL;}printk("led-gpio num = %d\r\n", gpioled.led_gpio);printk("led-gpio num = %d\r\n", gpioled.led1_gpio);/* 5.向gpio子系统申请使用GPIO */ret = gpio_request(gpioled.led_gpio, "LED-GPIO");if (ret){printk(KERN_ERR "gpioled: Failed to request led-gpio\n");return ret;}ret = gpio_request(gpioled.led1_gpio, "LED1-GPIO");if (ret){printk(KERN_ERR "gpioled1: Failed to request led-gpio\n");return ret;}/* 6、设置PI0为输出,并且输出低电平,默认关闭LED灯 */ret = gpio_direction_output(gpioled.led_gpio, 0);if (ret < 0){printk("can't set gpio!\r\n");}ret = gpio_direction_output(gpioled.led1_gpio, 0);if (ret < 0){printk("can't set gpio!\r\n");}/* 注册字符设备驱动 *//* 1、创建设备号 */if (gpioled.major){/* 定义了设备号 */gpioled.devid = MKDEV(gpioled.major, 0);ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);if (ret < 0){pr_err("cannot register %s char driver [ret=%d]\n", GPIOLED_NAME, GPIOLED_CNT);goto free_gpio;}}else{/* 没有定义设备号 */ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME); /* 申请设备号 */if (ret < 0){pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", GPIOLED_NAME, ret);goto free_gpio;}gpioled.major = MAJOR(gpioled.devid); /* 获取分配号的主设备号 */gpioled.minor = MINOR(gpioled.devid); /* 获取分配号的次设备号 */}printk("gpioled major=%d,minor=%d\r\n", gpioled.major, gpioled.minor);/* 2、初始化cdev */gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev, &gpioled_fops);/* 3、添加一个cdev */cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);if (ret < 0)goto del_unregister;/* 4、创建类 */gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if (IS_ERR(gpioled.class)){goto del_cdev;}/* 5、创建设备 */gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);if (IS_ERR(gpioled.device)){goto destroy_class;}return 0;destroy_class:class_destroy(gpioled.class);del_cdev:cdev_del(&gpioled.cdev);del_unregister:unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);free_gpio:gpio_free(gpioled.led_gpio);gpio_free(gpioled.led1_gpio);return -EIO;}

获取设备树中定义的节点,

然后自行匹配一下该设备是否 处于可用状态,以及是否为正确的compatible

,然后获取树中的两个gpio子节点,

并向系统申请使用这两个管脚,

对管脚设置输出方向并设置值关闭。

之后就是注册驱动的步骤:

创建设备号初始化cdev,设置字符设备属于该模块, 绑定fops结构体add cdev创建类及设备,自动生成节点

led_exit(void)

注销设备号,释放其他资源(cdev,class,devid,gpio)

设置file_operations,绑定操作

static int led_open(struct inode *inode, struct file *filp){filp->private_data = &gpioled; /* 设置私有数据 */return 0;}static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt){return 0;}static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt){int retvalue;unsigned char databuf[1];unsigned char ledstat;struct gpioled_dev *dev = filp->private_data;retvalue = copy_from_user(databuf, buf, cnt); /* 接收APP发送过来的数据 */if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];/* 获取状态值 */if(ledstat == SYSLEDON) {gpio_set_value(dev->led_gpio, 1);/* 打开sysLED灯 */} else if(ledstat == SYSLEDOFF) {gpio_set_value(dev->led_gpio, 0);/* 关闭sysLED灯 */} else if (ledstat == LEDON){gpio_set_value(dev->led1_gpio, 1);/* 打开LED灯 */}else if(ledstat == LEDOFF ){gpio_set_value(dev->led1_gpio,0); /*关闭LED灯*/}return 0;}static int led_release(struct inode *inode, struct file *filp){return 0;}/* 设备操作函数 */static struct file_operations gpioled_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,};

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。