dm6441的 gpio驱动

这是我进入嵌入式行业进公司做的第一个驱动,
平台:Ti   dm6441     linu2.6.18

GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。
由于硬件资源的原因,DM6441并不是GPIO管脚就是纯粹的GPIO脚,GPIO管脚和其他一些标准接口复用相同的引脚,
比如SPI和GPIO复用,I2C和GPIO复用等,到底是使用GPIO还是其他接口,在初始化的时候,都需要对PINMUX0和PINMUX1
两个寄存器进行设置(见DM6441的芯片p72),而软件设置则在Montavista linux-2.6.18_pro500/arch/arm/mach-davinci
目录下mux_cfg.c和对应的include/asm/arch-davinci/mux.h里。由数据手册知道gpio5,6,7默认是gpio功能。

对mux_cfg.c的分析

对MUX_CFG()的参数解释
   第一个是描述(和数据手册p72上要对应),第二个是pinmux0还是1,第三个是寄存器偏移。最后一个和调试有关的,
   倒数第二个就是你需要给pinmux寄存器相应位设置的值,倒数第三个就是pinmux相应位全为1的值(掩码值),
   倒数第四个就是pinmux相应位偏移值。如果你要改变引脚的模式,把对应引脚设置成0,再把其他功能设为1。
  (这是我的理解,参考下面的I2C和GPIO43_44设置)。
#include <linux/module.h>
#include <linux/init.h>

#include <asm/hardware.h>

#include <asm/arch/cpu.h>
#include <asm/arch/mux.h>

#ifdef CONFIG_DAVINCI_MUX

struct pin_config __initdata_or_module davinci_dm644x_pins[] = {
/*
 *  description  mux  mode   mode  mux  dbg
 *    reg  offset mask  mode
 */
MUX_CFG("HDIREN",   0,   16,    1,   1,  1)
MUX_CFG("ATAEN",   0,   17,    1,   1,  1)

MUX_CFG("MSTK",    1,   9,     1,   0,  0)

MUX_CFG("I2C",    1,   7,     1,   1,  0)

MUX_CFG("MCBSP",   1,   10,    1,   1,  0)

MUX_CFG("PWM0",    1,   4,     1,   1,  0)

MUX_CFG("PWM1",    1,   5,     1,   1,  0)

MUX_CFG("PWM2",    1,   6,     1,   1,  0)

MUX_CFG("VLINQEN",   0,   15,    1,   1,  0)
MUX_CFG("VLINQWD",   0,   12,    3,   3,  0)  //pinmux上面是2位在表示    所以0x11=3   3位就是111=7

MUX_CFG("EMACEN",   0,   31,    1,   1,  1)

MUX_CFG("GPIO3V",   0,   31,    1,   0,  1)

MUX_CFG("GPIO0",   0,   24,    1,   0,  1)
MUX_CFG("GPIO3",   0,   25,    1,   0,  0)
MUX_CFG("GPIO43_44",   1,   7,     1,   0,  0)
MUX_CFG("GPIO46_47",   0,   22,    1,   0,  1)

MUX_CFG("RGB666",   0,   22,    1,   1,  1)

MUX_CFG("LOEEN",   0,   24,    1,   1,  1)
MUX_CFG("LFLDEN",   0,   25,    1,   1,  0)
};

内核里提供的接口在linux-2.6.18_pro500/arch/arm/mach-davinci目录下的gpio.c,这个是寄存器级的驱动。对这个文件的相关操作
http://blog.csdn.net/langxing0508/archive/2008/12/25/3604043.aspx  达芬奇DM644X平台(ARM9, Linux-2.6.10)BSP之gpio.c浅析
说得不错,这里表示感谢。

下面是我的gpio驱动程序
 /* gpio driver*/

#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/arch/gpio.h>
#include <linux/types.h>
#include <linux/cdev.h>

#include <asm/arch-davinci/gpio.h>

#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/gpio.h>
//#include <asm/arch/regs-gpio.h>
#define DEVICE_NAME "dm644x_gpios"   /*定义设备驱动的名字,或设备节点名称*/
#define GPIO_MAJOR 199 /*使用 cat /proc/devices查看不要和存在的char节点重复*/
 
/*my app gpio define*/
#define ZX_GPIO5         5    /*GPIO5*/
#define ZX_GPIO6         6    /*GPIO6*/
#define ZX_GPIO7         7    /*GPIO7*/
 
static int davinci_dm644x_gpio_open(struct inode *inode, struct file *file)
{
 printk("open gpio,here is driver/n"); 
 const char *tag = NULL;
 int gpio5_value;
 int gpio6_value;
 int gpio7_value;

// gpio_request(ZX_GPIO6, tag);
// gpio_set_value(ZX_GPIO6, 0);
// __gpio_set(ZX_GPIO6, 0);
// printk("%s/n", tag);
 gpio_direction_output(ZX_GPIO5, 0);
 gpio_direction_output(ZX_GPIO6, 0);
 gpio_direction_output(ZX_GPIO7, 0);
 gpio5_value = gpio_get_value(ZX_GPIO5);
 gpio6_value = gpio_get_value(ZX_GPIO6);
 gpio7_value = gpio_get_value(ZX_GPIO7);

 printk("gpio5_value = %d, gpio6_value =%d , gpio7_value = %d/n", gpio5_value, gpio6_value, gpio7_value);
 return 0;/*该函数可以什么都不做,也可以加入类似初始化的设置*/
}
 
static int gpio_release(struct inode *inode,struct file *filp)
{
 return 0;
}


static int davinci_dm644x_gpio_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
  //  const char *tag;
    int   gpio5_value1;
     int   gpio5_value2;
    int   gpio6_value1;
       int   gpio6_value2;
    int   gpio7_value1;
       int   gpio7_value2;
       switch(cmd) /*cmd 表示应用程序传入的gpio动作,是on 还是off*/
       {
       case 0:     //gpio = 0
    
       /*if(0==arg) arg由自己硬件电路决定使用那些GPIO,我这里没有用这个扩展参数。应用程序就不能决定使用哪些gpio,
       完全由驱动程序去设置使用哪些。应用程序控制输出高低电平。所以下面的if语句全都要注释掉*/
      
           gpio_direction_output(ZX_GPIO5, 0);  /*调用TI linux-2.6.18寄存器驱动*/
      gpio_direction_output(ZX_GPIO6, 0);
      gpio_direction_output(ZX_GPIO7, 0);
      gpio5_value1 = gpio_get_value(ZX_GPIO5);
      gpio6_value1 = gpio_get_value(ZX_GPIO6);
      gpio7_value1 = gpio_get_value(ZX_GPIO7);
       printk("gpio5_value1 = %d, gpio6_value1 = %d, gpio7_value1 = %d/n", gpio5_value1, gpio6_value1,gpio7_value1);
         //    }
 /*             else if(1==arg)
              {
                      
           gpio_direction_output(ZX_GPIO6 , 0);
           gpio_set_value(ZX_GPIO6, 0);
           gpio_value = gpio_get_value(ZX_GPIO6);
   
           printk("gpio_value = %d/n", gpio_value); 
              }
              else if(2==arg)
              {
                     gpio_direction_output(ZX_GPIO7, 0);
              }
              else
              {
                     return -EINVAL;
              }*/
              break;
       case 1:            //gpio = 1
              //if(0==arg)
              //{
          // gpio_request(ZX_GPIO5, tag);
          // printk("cmd = 1, ZX_GPIO5= %d/n", ZX_GPIO5);
            gpio_direction_output(ZX_GPIO5, 1);  /*调用TI linux-2.6.18寄存器驱动*/
       gpio_direction_output(ZX_GPIO6, 1);
       gpio_direction_output(ZX_GPIO7, 1);
       gpio5_value2 = gpio_get_value(ZX_GPIO5);
       gpio6_value2 = gpio_get_value(ZX_GPIO6);
       gpio7_value2 = gpio_get_value(ZX_GPIO7);
      printk("gpio5_value2 = %d, gpio6_value2 =%d, gpio7_value2=%d/n", gpio5_value2, gpio6_value2, gpio7_value2);
              //}
              /*else if(1==arg)
              {
                      gpio_direction_output(ZX_GPIO6, 1);
           gpio_value = gpio_get_value(ZX_GPIO6);
           printk("gpio_value = %d/n", gpio_value);
              }
              else if(2==arg)
              {
                      gpio_direction_output(ZX_GPIO7, 1);
              }
              else
              {
                     return -EINVAL;
              }*/
              break;
       default:
              return -EINVAL;
       }
}
 
/*定义驱动设备文件API,在linux系统当中,任何设备都可以当做文件的方式操作,这一点和单片机和MCU有很大差别*/
static const struct file_operations davinci_dm644x_gpio_fileops = {
       .owner   = THIS_MODULE,
       .open    = davinci_dm644x_gpio_open,
       .ioctl   = davinci_dm644x_gpio_ioctl,
    .release = gpio_release
};
 
static int __init davinci_dm644x_gpio_init(void) /*内核初始化会调用该函数*/
{
       int ret;
 
       ret = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &davinci_dm644x_gpio_fileops);
       if(ret < 0)
       {
              printk(DEVICE_NAME " register falid!/n");
              return ret;
       }
 
       printk (DEVICE_NAME" initialized/n");
 
       return ret;
}
 
static void __exit davinci_dm644x_gpio_exit(void)
{
       unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);
}
 
module_init(davinci_dm644x_gpio_init);
module_exit(davinci_dm644x_gpio_exit);
 
MODULE_AUTHOR("xxx <>");
MODULE_DESCRIPTION("Davinci DM644x gpio driver");
MODULE_LICENSE("GPL");

下面是应用程序
/* dm644x_gpio_test.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
 
#define     on     (1)
#define     off    (0)
 
int main(void)
{
      
       int gpio_number = 0;
       int fd;
 


       fd = open("/dev/dm644x_gpios", 0);
       if (fd < 0)
       {
             perror("open device /dev/dm644x_gpios");
             exit(1);
       }
   
   printf("open gpio, here is app/n"); 
   sleep(1);
   printf("gpio_number = %d/n", gpio_number);
   sleep(1);  
    while (1) {  
       ioctl(fd, 1, 0);
    sleep(5);    
    ioctl(fd, 0, gpio_number);
    sleep(5);
   }       /*使5,6,7三个口循环的输出高低电平,便于用万用表测试*/
       close(fd);
       return 0;
}


下面是Makefile
#
# Makefile for the skeleton device drivers.
#

KDIR=/root/work/linux-2.6.18_pro500          # 内核目录
PWD := $(shell pwd)              #是指要编译的内核模块的源程序在哪个目录下,$(PWD)指与Makefile在同一目录下,也就是当前目录。


ifeq ($(KERNELRELEASE), )

modules:
 $(MAKE) -C $(KDIR) M=$(PWD) modules             #编译模块的规则,
 arm_v5t_le-gcc -o gpio_test app.c               #编译应用程序
 cp -f *.ko gpio_test /nfsroot/dm644x/filesys    #把编译好的驱动和应用程序复制到扳子的文件系统中去
 #scp char-reg.ko
[email protected]:/home/zlh/opt/filesystem
modules_install:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:                                                              #删除生成的所有文件
 rm -rf gpio_test *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
 #obj-m += skeleton_dev_class.o
 obj-m += gpio_driver.o      #你要编译的模块名称,这里必须和$(PWD)目录下C程序文件的名称相对应,如果C程序文件为world.c,那么必须修改成obj-m = world.o,也可
               #Obj-m = hello.o
               #Hello-objs = hello1.o, hello2.o   编译多个文件生成hello.o
endif


直接make 就行了    如果不行的话make ARCH=arm CROSS_COMPILE=arm_v5t_le-   加上编译工具

超级终端操作:
insmod  gpio_drive.ko
mknod  /dev/dm644x_gpios  c  199  0
./gpio_test  

你可能感兴趣的:(struct,Module,File,cmd,makefile,output)