龙空技术网

linux中的GPIO驱动

见字如疯 593

前言:

当前看官们对“linuxgpio驱动”可能比较注意,大家都想要知道一些“linuxgpio驱动”的相关内容。那么小编在网上收集了一些对于“linuxgpio驱动””的相关知识,希望姐妹们能喜欢,咱们快快来了解一下吧!

l 首先在设备树中添加GPIO节点,比如添加LED

内核源码目录下arch/arm/boot/dts/system-top.dts 文件,打开该文件,在根节点”/”下创建led节点,修改为如下:

Led{

Compatible = “alientek,led”;

Status = “okay”;

Default-state = “on”;

Led-gpio = <&gpio0 7 GPIO_ACTIVE_HIGH>;

};

分析如下:led-gpio属性指定了LED灯使用的GPIO,这里使用的GPIO0的IOO7(我使用的ZYNQ平台),可以依据不同平台修改。

l 在proc/device-tree目录下,可以看到各个驱动节点。可以看到有一个led-gpio文件,就是新添加的属性。

l Gpio驱动

#define GPIOLED_CNT 1 /* 设备号个数 */

#define GPIOLED_NAME "gpioled" /* 名字 */

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; /* LED 所使用的 GPIO 编号 */

};

static struct gpioled_dev gpioled;

45 /*

46 * @description : 打开设备

47 * @param – inode : 传递给驱动的 inode

48 * @param – filp : 设备文件, file 结构体有个叫做 private_data 的成员变量

49 * 一般在 open 的时候将 private_data 指向设备结构图。

50 * @return : 0 成功;其他 失败

51 */

52 static int led_open(struct inode *inode, struct file *filp)

53 {

54 filp->private_data = &gpioled; /* 设置私有数据 */

55 return 0;

56 }

static ssize_t led_read(struct file *filp, char __user *buf,

67 size_t cnt, loff_t *offt)

68 {

69 return 0;

70 }

71

72 /*

73 * @description : 向设备写数据

74 * @param – filp : 设备文件,表示打开的文件描述符

75 * @param – buf : 给设备写入的数据

76 * @param – cnt : 写入的数据长度

77 * @param – offt : 相对于文件首地址的偏移

78 * @return : 写入的字节数,如果为负值,表示写入失败

79 */

80 static ssize_t led_write(struct file *filp, const char __user *buf,

81 size_t cnt, loff_t *offt)

82 {

83 int ret;

84 char kern_buf[1];

85

86 ret = copy_from_user(kern_buf, buf, cnt); // 得到应用层传递过来的数据

87 if(0 > ret) {

88 printk(KERN_ERR "kernel write failed!\r\n");

89 return -EFAULT;

90 }

91

92 if (0 == kern_buf[0])

93 gpio_set_value(gpioled.led_gpio, 0); // 如果传递过来的数据是 0 则关闭 led

94 else if (1 == kern_buf[0])

95 gpio_set_value(gpioled.led_gpio, 1); // 如果传递过来的数据是 1 则点亮 led

96

97 return 0;

98 }

99

100 /*

101 * @description : 关闭/释放设备

102 * @param – filp : 关闭的设备文件(文件描述符)

103 * @return : 0 成功;其他 失败

104 */

105 static int led_release(struct inode *inode, struct file *filp)

106 {

107 return 0;

108 }

109

110 /* 设备操作函数 */

111 static struct file_operations gpioled_fops = {

112 .owner = THIS_MODULE,

113 .open = led_open,

114 .read = led_read,

115 .write = led_write,

116 .release = led_release,

117 };

118

119 static int __init led_init(void)

120 {

121 const char *str;

int ret;

124 /* 1.获取 led 设备节点 */

125 gpioled.nd = of_find_node_by_path("/led");

126 if(NULL == gpioled.nd) {

127 printk(KERN_ERR "gpioled: Failed to get /led node\n");

128 return -EINVAL;

129

}

130

131 /* 2.读取 status 属性 */

132 ret = of_property_read_string(gpioled.nd, "status", &str);

133 if(!ret) {

134 if (strcmp(str, "okay"))

135 return -EINVAL;

136

}

137

138 /* 2、获取 compatible 属性值并进行匹配 */

139 ret = of_property_read_string(gpioled.nd, "compatible", &str);

140 if(0 > ret) {

141 printk(KERN_ERR "gpioled: Failed to get compatible property\n");

142 return ret;

143

}

144

145 if (strcmp(str, "alientek,led")) {

146 printk(KERN_ERR "gpioled: Compatible match failed\n");

147 return -EINVAL;

148

}

149

150

printk(KERN_INFO "gpioled: device matching successful!\r\n");

151

152 /* 4.获取设备树中的 led-gpio 属性,得到 LED 所使用的 GPIO 编号 */

153 gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);

154 if(!gpio_is_valid(gpioled.led_gpio)) {

155 printk(KERN_ERR "gpioled: Failed to get led-gpio\n");

156 return -EINVAL;

157

}

158

159 printk(KERN_INFO "gpioled: led-gpio num = %d\r\n", gpioled.led_gpio);

160

161 /* 5.向 gpio 子系统申请使用 GPIO */

162 ret = gpio_request(gpioled.led_gpio, "LED-GPIO");

163 if (ret) {

164 printk(KERN_ERR "gpioled: Failed to request led-gpio\n");

165 return ret;

166

}

167

168 /* 6.将 led gpio 管脚设置为输出模式 */

169 gpio_direction_output(gpioled.led_gpio, 0);

170

171 /* 7.初始化 LED 的默认状态 */

172 ret = of_property_read_string(gpioled.nd, "default-state", &str);

173 if(!ret) {

174 if (!strcmp(str, "on"))

175 gpio_set_value(gpioled.led_gpio, 1);

176 else

177 gpio_set_value(gpioled.led_gpio, 0);

178 } else

179 gpio_set_value(gpioled.led_gpio, 0);

180

181 /* 8.注册字符设备驱动 */

182 /* 创建设备号 */

原子哥在线教学: 论坛:

727

183 if (gpioled.major) {

184 gpioled.devid = MKDEV(gpioled.major, 0);

185 ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);

186 if (ret)

187 goto out1;

188 } else {

189 ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);

190 if (ret)

191

goto out1;

192

193 gpioled.major = MAJOR(gpioled.devid);

194 gpioled.minor = MINOR(gpioled.devid);

195

}

196

197 printk("gpioled: major=%d,minor=%d\r\n",gpioled.major, gpioled.minor);

198

199 /* 初始化 cdev */

200 gpioled.cdev.owner = THIS_MODULE;

201

cdev_init(&gpioled.cdev, &gpioled_fops);

202

203 /* 添加一个 cdev */

204 ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);

205 if (ret)

206

goto out2;

207

208 /* 创建类 */

209 gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);

210 if (IS_ERR(gpioled.class)) {

211 ret = PTR_ERR(gpioled.class);

212 goto out3;

213

}

214

215 /* 创建设备 */

216 gpioled.device = device_create(gpioled.class, NULL,

217 gpioled.devid, NULL, GPIOLED_NAME);

218 if (IS_ERR(gpioled.device)) {

219 ret = PTR_ERR(gpioled.device);

220 goto out4;

221

}

222

223 return 0;

标签: #linuxgpio驱动