Linux驱动开发(一):使用pinctrl,gpio子系统点灯(野火imx6ull-mini开发板)

一:修改设备树文件

iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_led”的子节点

pinctrl_led: ledgrp {
			fsl,pins = <
				MX6UL_PAD_GPIO1_IO04__GPIO1_IO04    0x10B0 /* LED1 */
				MX6UL_PAD_GPIO1_IO09__GPIO1_IO09    0x10B0 /* LED2 */
				MX6UL_PAD_GPIO1_IO08__GPIO1_IO08	0x10B0 /* LED3 */
			>;
		};

二:添加 LED 设备节点

在根节点“/”下创建 LED 灯节点,节点名为“gpioled”

	gpioled{
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "fireMini,gpioled";
		pinctrl-name = "default";
		pinctrl-0 = <&pinctrl_led>;
		led1-gpio = <&gpio1 4 GPIO_ACTIVE_LOW>;
		led2-gpio = <&gpio1 9 GPIO_ACTIVE_LOW>;
		led3-gpio = <&gpio1 8 GPIO_ACTIVE_LOW>;
		status = "okay";
	}

(1)pinctrl-0 属性设置 LED 灯所使用的 PIN 对应的 pinctrl 节点
(2)led1-gpio 属性指定了 LED 灯所使用的 GPIO,在这里就是 GPIO1 的 IO04,低电平
有效。稍后编写驱动程序的时候会获取 led-gpio 属性的内容来得到 GPIO 编号,因为 gpio 子系
统的 API 操作函数需要 GPIO 编号。led2-gpio,led3-gpio类似

三:编写驱动程序

1.驱动的入口和出口函数

我们在编写驱动的时候需要注册这两种操作函数,模块的加载和卸载注册函数如下:

module_init(xxx_init);
module_exit(xxx_exit);
//注册模块加载函数
//注册模块卸载函数

module_init 函数用来向 Linux 内核注册一个模块加载函数,参数 xxx_init 就是需要注册的
具体函数,当使用“insmod”命令加载驱动的时候, xxx_init 这个函数就会被调用。 module_exit()
函数用来向 Linux 内核注册一个模块卸载函数,参数 xxx_exit 就是需要注册的具体函数,当使
用“rmmod”命令卸载具体驱动的时候 xxx_exit 函数就会被调用。字符设备驱动模块加载和卸
载模板如下所示:
 

static int __init xxx_init(void)
{
     /* 入口函数具体内容 */
     return 0;
}
/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
 /* 出口函数具体内容 */
}

/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(xxx_init);
module_exit(xxx_exit);

2.注册字符设备驱动

对于字符设备驱动而言,当驱动模块加载成功以后需要注册字符设备,同样,卸载驱动模
块的时候也需要注销掉字符设备。字符设备的注册和注销函数原型如下所示:
 

设备号分配方式有两种,一种是主动设置设备号,另外一种是动态分配设备号,在实际开发中主要是动态分配

/* 1.注册字符设备驱动 */
	gpioled.major = 0;
	if(gpioled.major){
		gpioled.devid = MKDEV(gpioled.major,0);
		register_chrdev_region(gpioled.devid,GPIOLED_CNT,GPIOLED_NAME);
	}else{   	
		alloc_chrdev_region(&gpioled.devid,0,GPIOLED_CNT,GPIOLED_NAME);
		gpioled.major = MAJOR(gpioled.devid);
		gpioled.minor = MINOR(gpioled.devid);
	}

3.初始化cdev 

在 Linux 中使用 cdev 结构体表示一个字符设备, cdev 结构体在 include/linux/cdev.h 文件中
的定义如下:
 

struct cdev {
 struct kobject kobj;
 struct module *owner;
 const struct file_operations *ops;
 struct list_head list;
 dev_t dev;
 unsigned int count;
};

在 cdev 中有两个重要的成员变量: ops 和 dev,这两个就是字符设备文件操作函数集合
file_operations 以及设备号 dev_t。编写字符设备驱动之前需要定义一个 cdev 结构体变量,这个
变量就表示一个字符设备。

定义好 cdev 变量以后就要使用 cdev_init 函数对其进行初始化, cdev_init 函数原型如下:
void cdev_init(struct cdev *cdev, const struct file_operations *fops)

cdev_add 函数用于向 Linux 系统添加字符设备(cdev 结构体变量),首先使用 cdev_init 函数
完成对 cdev 结构体变量的初始化,然后使用 cdev_add 函数向 Linux 系统添加这个字符设备。
cdev_add 函数原型如下:
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
卸载驱动的时候一定要使用 cdev_del 函数从 Linux 内核中删除相应的字符设备, cdev_del
函数原型如下:
void cdev_del(struct cdev *p)
参数 p 就是要删除的字符设备。如果要删除字符设备,参考如下代码:
示例代码 42.1.2.3 cdev_del 函数使用示例
1 cdev_del(&testcdev); /* 删除 cdev */
cdev_del 和 unregister_chrdev_region 这两个函数合起来的功能相当于 unregister_chrdev 函

6.创建类class

自动创建设备节点的工作是在驱动程序的入口函数中完成的,一般在 cdev_add 函数后面添
加自动创建设备节点相关代码。首先要创建一个 class 类, class 是个结构体,定义在文件
include/linux/device.h 里面。 class_create 是类创建函数, class_create 是个宏定义,内容如下:
 

1 #define class_create(owner, name) \
2 ({ \
3 static struct lock_class_key __key; \
4 __class_create(owner, name, &__key); \
5 })
6 7
struct class *__class_create(struct module *owner, const char *name,
8 struct lock_class_key *key

根据上述代码,将宏 class_create 展开以后内容如下:
struct class *class_create (struct module *owner, const char *name)
class_create 一共有两个参数,参数 owner 一般为 T

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ethan_LiuQuan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值