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!

");
 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
",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!

");
 78     
 79     return 1;
 80 }
 81 
 82 static int  key_release(struct inode *inode, struct file *filp)
 83 {
 84     printk("<0>function release!

");
 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!

");
 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

");
115             break;
116         default:
117               printk("<0>command error 
");
118             printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;
");
119             printk("<0>command: <key_input> <version>

");
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>
Hello,this is %s module!

",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 !
");
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>
Goodbye,%s!

",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);

时,就会执行

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 !!!
");
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
",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*

 结果如下:

执行应用程序:

cd key/

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

./key_test

结果如下:

原文地址:https://www.cnblogs.com/lihaiyan/p/4294510.html