读书人

途一个GPIO驱动

发布时间: 2012-08-25 10:06:20 作者: rapoo

谈一个GPIO驱动

谈一个GPIO驱动

一切的操作其实都是gpio的变化,这也就是说gpio驱动是基本的入门,我想很多人应该对gpio都不陌生,从单片机stc89开始,一直都伴随着gpio的操作。mov P1 ,XX 之类的,不过如今咱们已经升级到arm上面的开发了,其实arm只是名字换了,操作也还是那样。所以今天我就献丑来谈一下关于arm11 s3c6410上面的gpio操作的驱动。。

首先必须了解的就是io口的一些要素,在stc89上,其实并不是特别明显,要输出就写入,要读取就直接读就好了(先写1再读取)。但一些稍显高级的片子就不同了,一般将io会增加了输入输出模式的控制,和数据引脚的寄存器。这就一下子多了2个寄存器出来了,一般称作CON DAT这2个寄存器,CON用来配置引脚工作在输出模式还是输入模式,而DAT寄存器对应的就是引脚的值了,输出就往里面写值,输入则是读取。。而arm则还有PUL寄存器,也叫上拉寄存器,上拉可以保证引脚任何时候都有确定的值,不受干扰。这些就是gpio的一些基本信息。

有了上述的基本信息之后,对于gpio驱动也就不是那么难以入手了。简单的说明下假设输出为0x0001 输入为0x0000 那么将引脚配置为输出1 那就是CON = 0x0001 DAT = 1

就是这么简单,关键是怎么去写这个寄存器的问题了。

首先我这里以s3c6410 GPM作为例子来写一个GPM驱动程序。首先先建立platform文件,将资源加载到bus上。


途一个GPIO驱动

途一个GPIO驱动途一个GPIO驱动


对照着上面的配置情况,写入具体的数值,那么对应的管脚也会有相应的电平反映的。。。

好了。。该篇就写到这。。有不明白的,还望留言,我会第一时间回复各位。。谢谢


#include <linux/init.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/ioctl.h>#include <linux/slab.h>//kmalloc kfree#include <linux/errno.h>#include <asm/uaccess.h>//copy_to_user copy_from_user_user#include <linux/device.h>#include <linux/spinlock.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/platform_device.h>#include <linux/io.h>#include <asm/io.h>//readl()#include <mach/irqs.h>//中断号#include <linux/irq.h>//中断函数#include <linux/interrupt.h>//中断类型#include <linux/timer.h>#include <linux/poll.h>#include <linux/gpio.h>#include <plat/gpio-cfg.h>#include <mach/regs-gpio.h>#include "register_cdev.h"#include "gpio_m_info.h"#define _DEBUG_#define CHR_NAME"gpio_m"#define CLASS_NAME"chass_gpio_m"#define DEVICE_NAME"device_gpio_m"//结构体声明,字符设备结构体struct device_dev{struct cdev cdev;struct class *my_class;GPIO_M_INFO*gpm;spinlock_tspin;//自旋锁,实现内存的互斥操作};struct device_dev *g_devp;//设备结构指针//默认主设备号,0为自动分配,否则外部设置 int g_major = 0;static int gpio_m_open(struct inode *inode,struct file *filp){/*将设备结构体指针赋给文件私有数据指针*/struct device_dev *devp;devp = container_of(inode->i_cdev,struct device_dev,cdev);filp->private_data = devp;/*判断文件打开的标志*/return 0;}static int gpio_m_release(struct inode *inode,struct file *filp){struct device_dev *devp;devp = filp->private_data;return 0;}static void set_cfg(unsigned int dat,unsigned int pin,struct device_dev *devp){unsigned int temp;spin_lock(&devp->spin);temp = devp->gpm->gpmcon;temp &= (~((0x0F) << (pin << 2)));temp |= ((dat) << (pin << 2));devp->gpm->gpmcon = temp;spin_unlock(&devp->spin);}static void set_dat(unsigned int dat,unsigned int pin,struct device_dev *devp){spin_lock(&devp->spin);if(dat){devp->gpm->gpmdat |= (0x01 << pin);}else{devp->gpm->gpmdat &= ~(0x01 << pin);}spin_unlock(&devp->spin);}static void set_pull(unsigned int dat,unsigned int pin,struct device_dev *devp){unsigned int temp;spin_lock(&devp->spin);temp = devp->gpm->gpmpud;temp &= (~((0x03) << (pin << 1))); temp |= ((dat) << (pin << 1));devp->gpm->gpmpud = temp;spin_unlock(&devp->spin);}static long gpio_m_unlocked_ioctl(struct file *filp,unsigned int cmd,unsigned long arg){int i = 0;int flag = 0;struct device_dev *devp;devp = filp->private_data;switch(cmd){case GPM_SET_OUT_BIT:flag++;case GPM_SET_IN_BIT:set_cfg(flag,arg,devp);break;case GPM_SET_MUT_OUT_BIT:flag++;case GPM_SET_MUT_IN_BIT:for(i = 0; arg;i++){if(arg & 0x01)set_cfg(flag,i,devp);arg >>= 1;}break;case GPM_SET_DAT:flag++;case GPM_CLR_DAT:set_dat(flag,arg,devp);break;case GPM_SET_MUT_DAT:flag++;case GPM_CLR_MUT_DAT:for(i = 0; arg;i++){if(arg & 0x01)set_dat(flag,i,devp);arg >>= 1;}break;case GPM_SET_PULL_UP:flag++;case GPM_SET_PULL_DOWN:flag++;case GPM_SET_PULL_DISABLE:set_pull(flag,arg,devp);break;case GPM_SET_MUT_PULL_UP:flag++;case GPM_SET_MUT_PULL_DOWN:flag++;case GPM_SET_MUT_PULL_DISABLE:for(i = 0; arg;i++){if(arg & 0x01)set_dat(flag,i,devp);arg >>= 1;}break;default:break;}return 0;}//设置字符设备对应的fopsstatic struct file_operations device_fops = {  .owner= THIS_MODULE,  .open= gpio_m_open,  .release= gpio_m_release,.unlocked_ioctl = gpio_m_unlocked_ioctl,}; static int get_resource(struct device_dev* dev,struct platform_device *pfdev){struct resource *mem_res;struct resource*gpm_mem;mem_res = platform_get_resource(pfdev,IORESOURCE_MEM,0);if(NULL == mem_res){return -ENOENT;}/* 将指定的内存段标明已被使用,防止其它程序再次加载 */gpm_mem = request_mem_region(mem_res->start,resource_size(mem_res),pfdev->name);if(NULL == gpm_mem){return -EBUSY;}/* ioremap是架构的问题产生的,应为早起的intel的芯片其io寄存器并不是统一编址,并不能直接操作内存那样访问,所以需要将其映射到内存地址 */dev->gpm = ioremap(mem_res->start,resource_size(mem_res));if(NULL == dev->gpm){release_mem_region(mem_res->start, resource_size(mem_res));return -EINVAL;}#ifdef _DEBUG_printk(KERN_INFO "GPMCON : 0x%08x\n",dev->gpm->gpmcon);printk(KERN_INFO "GPMDAT : 0x%08x\n",dev->gpm->gpmdat);printk(KERN_INFO "GPMPUD : 0x%08x\n",dev->gpm->gpmpud);#endifreturn 0;}static void free_memory(struct device_dev* dev,struct platform_device *pdev){struct resource *mem_res;iounmap((void *) dev->gpm);dev->gpm = NULL;mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (mem_res != NULL)release_mem_region(mem_res->start, resource_size(mem_res));if(dev){kfree(dev);g_devp = 0;}}static int __devinit key_probe(struct platform_device *dev){/*初始化代码*/int result;//分配设备结构体空间g_devp = kmalloc(sizeof(struct device_dev),GFP_KERNEL);if (!g_devp) {result = -ENOMEM;return -ENOMEM;}memset(g_devp,0,sizeof(struct device_dev));/* 获取platform资源(按键信息) */if((result = get_resource(g_devp,dev)),result){return result;}spin_lock_init(&g_devp->spin);/* 申请设备号,关联file_operation并生成设备文件 */result = register_setup(&g_major,&(g_devp->cdev),&device_fops,CHR_NAME,CLASS_NAME,DEVICE_NAME,&(g_devp->my_class) );if(result){free_memory(g_devp,dev);}printk(KERN_INFO "Sucessful init_function magor = %d\n",g_major);return result;}static int __devexit key_remove(struct platform_device *dev){/*释放代码*/unregister_setup(g_major,&(g_devp->cdev),g_devp->my_class);free_memory(g_devp,dev);//释放已申请的内存printk(KERN_INFO "Sucessful cleanup_function\n");return 0; }static struct platform_driver my_driver = {.probe= key_probe,.remove = __devexit_p(key_remove),.driver = {.name = "gpio_m",.owner = THIS_MODULE,}};static int __init initialization_function(void){return platform_driver_register(&my_driver);}static void __exit cleanup_function(void){platform_driver_unregister(&my_driver);}//注册模块加载卸载函数module_init(initialization_function);//指定模块加载函数module_exit(cleanup_function);//指定模块卸载函数//模块参数module_param(g_major,int,S_IRUGO);               //导出参数,为了人工设定主设备号//模块信息及许可证MODULE_AUTHOR("LvApp");//作者MODULE_LICENSE("Dual BSD/GPL");//许可证MODULE_DESCRIPTION("A simple GPM module");//描述MODULE_ALIAS("GPM");//别名


读书人网 >编程

热点推荐