arm11 Tiny6410 gpio驱动实现输入和输出
扫描二维码
随时随地手机看文章
这个驱动人家都说很简单,因为需要,所以我自己写了一个。
其实最后发现要是初学者写这个驱动还是不简单的,问了好多人,发了好多帖子,会的人寥寥无几啊,网上贴的都是一些只有中断输入button和只有输出的led的demo,很难使用,我把我写好的给大家分享下,大家有什么问题可以直接问我。
我把需要注意的地方列出来
在以前常见的GPIO作为中断使用的时候,一般做以下步骤即可:
* 设置GPIO复用功能为 一般的GPIO功能;
* 设置GPIO为input状态;
* 设置产生中断的方式;上升延,还是下降延;
* 设置中断控制器 enable GPIO_X位
下面是我的驱动代码,本来说实现16位输入16位输出的,现在先把1位输入和1位输出贴出来:
//gpio_drv.c #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME "usr_gpio" #define GPIO_INPUT_0 S3C64XX_GPN(0)//按键key1 #define GPIO_OUTPUT_0 S3C64XX_GPK(5)//灯led2 #define GPIO_INNUM 1 #define GPIO_OUTNUM 1 short temp; int gpio_irq = IRQ_EINT(0); struct workqueue_struct *gpio_queue; struct work_struct gpio_wq; void goio_do_work(unsigned long data); static unsigned long input_table[] = { GPIO_INPUT_0, }; static unsigned long output_table[] = { GPIO_OUTPUT_0 }; //中断处理底半部 void gpio_do_work(unsigned long data) { int i, val; for (i = 0; i < GPIO_INNUM; i++) { val = gpio_get_value(input_table[i]); temp |= ((val&0x1) << i); } } //中断处理顶半部 irqreturn_t read_interrupt(int irq, void *dev_id) { printk("int the read_interruptn"); queue_work(gpio_queue, &gpio_wq); return IRQ_HANDLED; } static int gpio_input_init(void) { int ret = 0, i = 0; for (i = 0; i < GPIO_INNUM; i++) { if (gpio_is_valid(input_table[i]) == -EINVAL) { printk("ERROR, GPIO used for input port is using by other devices !"); break; } //设置上拉 s3c_gpio_setpull(input_table[i], S3C_GPIO_PULL_DOWN); //设置为输入 s3c_gpio_cfgpin(input_table[i], S3C_GPIO_SFN(0)); } return ret; } static int gpio_output_init(void) { int ret = 0, i = 0; for (i = 0; i < GPIO_OUTNUM; i++) { if (gpio_is_valid(output_table[i]) == -EINVAL) { printk("ERROR, GPIO used for output port is using by other devices !"); break; } //设置上拉 s3c_gpio_setpull(output_table[i], S3C_GPIO_PULL_UP); //设置为输出 s3c_gpio_cfgpin(output_table[i], S3C_GPIO_SFN(1)); //设置引脚电平状态 gpio_set_value(output_table[i], 1); } return ret; } int gpio_open(struct inode *inode,struct file *filp) { int ret; ret = request_irq(gpio_irq, read_interrupt, IRQF_TRIGGER_RISING, DEVICE_NAME, NULL); if (ret < 0) { printk("ERROR, irq %d can not be requested !n", gpio_irq); return -EBUSY; } else printk("OK,ret=%dn",ret); gpio_queue = create_workqueue("gpio_queue"); //初始化工作队列 INIT_WORK(&gpio_wq, (void *)gpio_do_work); return 0; } int gpio_release(struct inode *inode,struct file *filp) { //释放中断 disable_irq(gpio_irq); destroy_workqueue(gpio_queue); return 0; } ssize_t gpio_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { unsigned long err; count = sizeof(temp); printk("temp=%dn", temp); err = copy_to_user(buf,&temp, count); return err ? -EFAULT : count; } ssize_t gpio_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { int i = 0; printk("%dn", buf[0]); for (i = 0; i < GPIO_OUTNUM; i++) { if(((buf[0]>>i)&0x1)== 1) gpio_set_value(output_table[i], 1); if(((buf[0]>>i)&0x1) == 0) gpio_set_value(output_table[i], 0); } return 0; } static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = gpio_open, .release = gpio_release, .read=gpio_read, .write=gpio_write, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops }; //设备驱动模块加载函数 static int __init dev_init(void) { int ret; //初始化输入输出引脚 gpio_input_init(); gpio_output_init(); //注册混杂设备结构体 ret = misc_register(&misc); if (ret < 0) { printk("ERROR, misc_register error"); return ret; } printk(DEVICE_NAME"t initializedn"); return ret; } //设备驱动模块卸载函数 static void __exit dev_exit(void) { disable_irq(gpio_irq); free_irq(gpio_irq, read_interrupt); //注销混杂设备结构体 misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("CAIHUI.");
//gpio_test.c
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int pin_state;
int pin_no;
int fd;
char n[4];
unsigned int bytes = 0;
fd = open("/dev/usr_gpio", O_RDWR);
if (fd < 0)
{
perror("open device /dev/usr_gpio");
exit(1);
}
sleep(10);
//while(1)
{
read(fd, n, 1);
printf("%dn", n[0]);
}
printf("outn");
close(fd);
return 0;
}
#Makefile
CC = arm-linux-gcc
obj-m := gpio_drv.o
PWD := $(shell pwd)
KDIR := /home/huicai/new-work/linux-2.6.38
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
代码有点问题就是模块注销的时候不能释放中断号,中断组不能用,目前正在找原因。有知道原因的朋友可以告诉我下,谢谢