20150216 IMX257实现GPIO-查询按键驱动程序

20150216IMX257实现GPIO-查询按键驱动程序

2015-02-16 李海沿

前面我们介绍了简单的通用字符设备驱动程序,接下来,我们在它的基础上来实现GPIO的查询按键功能。

先附上驱动程序代码

 

  1 /******************************

  2     linux key_query

  3  *****************************/

  4 #include <linux/module.h>

  5 #include <linux/init.h>

  6 #include <linux/kernel.h>

  7 #include <linux/delay.h>

  8 #include <linux/types.h>

  9 #include <linux/ioctl.h>

 10 #include <linux/gpio.h>

 11 #include <linux/fs.h>

 12 #include <linux/device.h>//包含了用于自动创建设备节点的函数device_create

 13 #include <linux/uaccess.h>//包含了copy_to_user 函数等

 14 

 15 #include "mx257_gpio.h"

 16 #include "mx25_pins.h"

 17 #include "iomux.h"

 18 

 19 #define Driver_NAME "key_query"

 20 #define DEVICE_NAME "key_query"

 21 

 22 #define GPIO2_21    MX25_PIN_CLKO

 23 #define GPIO3_15    MX25_PIN_EXT_ARMCLK

 24 #define GPIO2_10    MX25_PIN_A24

 25 #define GPIO2_11    MX25_PIN_A25

 26 #define GPIO2_8     MX25_PIN_A22

 27 #define GPIO2_9     MX25_PIN_A23

 28 #define GPIO2_6     MX25_PIN_A20

 29 #define GPIO2_7     MX25_PIN_A21

 30 //command

 31 #define key_input     0

 32 #define version        1

 33 //用于保存主设备号

 34 static int major=0;

 35 //用于自动创建设备节点 代替了手动敲mknod命令

 36 //auto to create device node

 37 static struct class *drv_class = NULL;

 38 static struct class_device *drv_class_dev = NULL;

 39 

 40 

 41 /* 应用程序对设备文件/dev/key_query执行open(...)时,

 42  * 就会调用key_open函数*/

 43 static int key_open(struct inode *inode, struct file *file)

 44 {

 45     printk("<0>function open!\n\n");

 46     

 47     return 0;

 48 }

 49 /*当应用程序中read(fd,buff,sizeof(buff))时调用此key_read函数*/

 50 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

 51 {

 52     int ret;

 53     //nt cnt=0;

 54     unsigned char key_vals[8];

 55     // reading the pins value

 56     key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0;

 57     key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0;

 58     key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0;

 59     key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0;

 60     key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0;

 61     key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0;

 62     key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0;

 63     key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0;

 64     

 65     ret = copy_to_user(buff,key_vals,sizeof(key_vals));

 66     if(ret){

 67         ;

 68     }

 69     

 70     //printk("<0>%04d key pressed: %d %d %d %d %d %d %d %d\n",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]); 

 71 

 72     return sizeof(key_vals);

 73 }

 74  /* 当应用程序中使用write函数时,调用此函数**/

 75 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

 76 {

 77     printk("<0>function write!\n\n");

 78     

 79     return 1;

 80 }

 81 

 82 static int  key_release(struct inode *inode, struct file *filp)

 83 {

 84     printk("<0>function release!\n\n");

 85     return 0;

 86 }

 87  /* 当用户调用ioctl(fd,version,NULL);时,会进入此函数,

 88   * 在SWITCH中配对command,然后执行相应的语句 

 89   * 注意command 一定为整数,需在前面定义*/

 90 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)

 91 {

 92     printk("<0>function ioctl!\n\n");

 93     switch (command) {

 94         case key_input:

 95             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21));

 96             gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15));

 97             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));

 98             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11));

 99             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8));

100             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9));

101             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6));

102             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7));

103             //设置所有引脚为上拉模式

104             mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

105             mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

106             //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

107             mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

108             mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

109             mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

110             mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

111             //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

112             break;

113         case version:

114             printk("<0>hello,the version is 0.1.0\n\n");

115             break;

116         default:

117               printk("<0>command error \n");

118             printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n");

119             printk("<0>command: <key_input> <version>\n\n");

120             return -1;

121     }

122     return 0;    

123 }

124 

125 /* 这个结构是字符设备驱动程序的核心

126  * 当应用程序操作设备文件时所调用的open、read、write等函数,

127  * 最终会调用这个结构中指定的对应函数

128  */

129 static struct file_operations key_fops = {

130     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

131     .open   =   key_open,     

132     .read    =    key_read,       

133     .write    =    key_write,       

134     .release=   key_release,

135     .ioctl  =   key_ioctl,    

136 };

137     

138 /*

139  * 执行insmod命令时就会调用这个函数 

140  */

141 static int __init key_init(void)

142 {

143     printk("<0>\nHello,this is %s module!\n\n",Driver_NAME);

144     //register and mknod

145     //注册字符设备,系统会自动分配一个主设备号,保存在major中

146     major = register_chrdev(0,Driver_NAME,&key_fops);

147     //自动在/dev/目录下创建设备节点

148     drv_class = class_create(THIS_MODULE,Driver_NAME);

149     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);    /*/dev/key_query*/

150 

151     //set all pins to GPIO mod  ALF5

152     //设置所有的GPIO引脚为GPIO功能

153     mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5);

154     mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5);

155       mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5);

156        mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5);

157     mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5);

158     mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5);

159     mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5);

160     mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5);

161     

162     

163             printk("<0>have setting all pins to gpio input mod !\n");

164     //request IOMUX GPIO

165     gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21");

166      gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15");

167      gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10");

168        gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11");

169     gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8");

170      gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9");

171       gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6");

172     gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7");

173 

174     return 0;

175 }

176 

177 /*

178  * 执行rmmod命令时就会调用这个函数 

179  */

180 static void __exit key_exit(void)

181 {

182     printk("<0>\nGoodbye,%s!\n\n",Driver_NAME);

183     //卸载字符设备,释放主设备号

184     unregister_chrdev(major,Driver_NAME);

185     //卸载字符设备的设备节点

186     device_unregister(drv_class_dev);

187     class_destroy(drv_class);

188 

189     /* free gpios */

190     mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5);

191     mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5);

192     mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5);

193     mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5);

194     mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5);

195     mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5);

196     mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5);

197     mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5);

198 

199     gpio_free(IOMUX_TO_GPIO(GPIO2_21));

200     gpio_free(IOMUX_TO_GPIO(GPIO3_15));

201     gpio_free(IOMUX_TO_GPIO(GPIO2_10));

202     gpio_free(IOMUX_TO_GPIO(GPIO2_11));

203     gpio_free(IOMUX_TO_GPIO(GPIO2_8));

204     gpio_free(IOMUX_TO_GPIO(GPIO2_9));

205     gpio_free(IOMUX_TO_GPIO(GPIO2_6));

206     gpio_free(IOMUX_TO_GPIO(GPIO2_7));

207 

208 }

209 

210 /* 这两行指定驱动程序的初始化函数和卸载函数 */

211 module_init(key_init);

212 module_exit(key_exit);

213 

214 /* 描述驱动程序的一些信息,不是必须的 */

215 MODULE_AUTHOR("Lover雪");

216 MODULE_VERSION("0.1.0");

217 MODULE_DESCRIPTION("IMX257 key Driver");

218 MODULE_LICENSE("GPL");
key.c

 

 


如程序所示,
 

static int __init key_init(void)

我们把注册字符设备,创建设备节点,GPIO地址映射,以及GPIO模式的初始化,都在此函数中实现。

 

static void __exit key_exit(void)

在此函数中我们 做了一下三件事,卸载字符设备,释放主设备函,释放GPIO

 

static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

当应用程序中调用

read(fd, key_vals,sizeof(key_vals));

时,该函数就是负责,读取此时,我们GPIO引脚的电平,然后通过COPY_TO_USER函数将我们的gpio引脚的电平传递给应用程序。

 

static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)

当应用程序中,执行代码

ioctl(fd,key_input,NULL);

时,就会执行

20150216 IMX257实现GPIO-查询按键驱动程序

switch的case key_input中的代码,将所有的gpio引脚都设置成输入模式。

 然后将所有的GPIO引脚设置为22K上拉模式:

//设置所有引脚为上拉模式

            mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

            //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

 

经过测试,貌似,GPIO2_8,GPIO3_15两个引脚不能这样设置,由于暂时对IMX257还不太了解,对于这一现象无法解释。

 

附上应用程序代码

 1 #include <stdio.h>

 2 #include <stdlib.h>

 3 #include <unistd.h>

 4 #include <sys/types.h>

 5 #include <sys/stat.h>

 6 #include <fcntl.h>

 7 #include <termios.h>

 8 #include <errno.h>

 9 #include <limits.h>

10 #include <asm/ioctls.h>

11 #include <time.h>

12 #include <pthread.h>

13 

14 #include "mx257_gpio.h"

15 

16 #define key_input     0

17 #define version               1

18 

19 

20 int main(int argc, char **argv)

21 {

22     int fd;

23     int i=0,cnt=0;

24     unsigned char key_vals[8];

25     

26     fd = open("/dev/key_query",O_RDWR);

27     if(fd < 0){

28         printf("can't open !!!\n");

29     }

30     ioctl(fd,key_input,NULL);

31     while(1){

32         read(fd, key_vals,sizeof(key_vals));

33         if(!key_vals[0] | !key_vals[1] | !key_vals[2] | !key_vals[3] | !key_vals[4] | !key_vals[5] | !key_vals[6] | !key_vals[7] )

34             printf("%04d key pressed: %d %d %d %d %d %d %d %d\n",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]);    

35     }

36     return 0;

37 }
View Code

 


在应用程序中,
 

  1. 我们首先使用open来打开设备/dev/key_query。
  1. 使用ioctl函数将所有的GPIO引脚配置为输入模式
  1. 在while循环中使用read函数来不断的读取gpio引脚的电,一旦检测到低电平,就打印所有GPIO引脚当前的电平值

 

附上MAKEFILE代码

 1 ifeq ($(KERNELRELEASE),)

 2     KERNELDIR ?= /home/study/system/linux-2.6.31

 3     PWD := $(shell pwd)

 4 modules:

 5     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

 6 modules_install:

 7     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

 8 clean:

 9     rm -rf *.o *~ core .depend  *cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers

10 

11 else

12     obj-m := key.o

13 endif
View Code

 


 
 

 

编译、加载驱动:

使用交叉编译工具:

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

insmod key.ko

ll /dev/key*

 结果如下:

20150216 IMX257实现GPIO-查询按键驱动程序

执行应用程序:

cd key/

arm-none-linux-gnueabi-gcc key_test.c –o key_test

./key_test

结果如下:

20150216 IMX257实现GPIO-查询按键驱动程序

 

20150216 IMX257实现GPIO-查询按键驱动程序

 

你可能感兴趣的:(IO)