arm11 Tiny6410 gpio驅(qū)動實現(xiàn)輸入和輸出
這個驅(qū)動人家都說很簡單,因為需要,所以我自己寫了一個。
其實最后發(fā)現(xiàn)要是初學(xué)者寫這個驅(qū)動還是不簡單的,問了好多人,發(fā)了好多帖子,會的人寥寥無幾啊,網(wǎng)上貼的都是一些只有中斷輸入button和只有輸出的led的demo,很難使用,我把我寫好的給大家分享下,大家有什么問題可以直接問我。
我把需要注意的地方列出來
在以前常見的GPIO作為中斷使用的時候,一般做以下步驟即可:
* 設(shè)置GPIO復(fù)用功能為 一般的GPIO功能;
* 設(shè)置GPIO為input狀態(tài);
* 設(shè)置產(chǎn)生中斷的方式;上升延,還是下降延;
* 設(shè)置中斷控制器 enable GPIO_X位
下面是我的驅(qū)動代碼,本來說實現(xiàn)16位輸入16位輸出的,現(xiàn)在先把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; } //設(shè)置上拉 s3c_gpio_setpull(input_table[i], S3C_GPIO_PULL_DOWN); //設(shè)置為輸入 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; } //設(shè)置上拉 s3c_gpio_setpull(output_table[i], S3C_GPIO_PULL_UP); //設(shè)置為輸出 s3c_gpio_cfgpin(output_table[i], S3C_GPIO_SFN(1)); //設(shè)置引腳電平狀態(tài) 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 }; //設(shè)備驅(qū)動模塊加載函數(shù) static int __init dev_init(void) { int ret; //初始化輸入輸出引腳 gpio_input_init(); gpio_output_init(); //注冊混雜設(shè)備結(jié)構(gòu)體 ret = misc_register(&misc); if (ret < 0) { printk("ERROR, misc_register error"); return ret; } printk(DEVICE_NAME"t initializedn"); return ret; } //設(shè)備驅(qū)動模塊卸載函數(shù) static void __exit dev_exit(void) { disable_irq(gpio_irq); free_irq(gpio_irq, read_interrupt); //注銷混雜設(shè)備結(jié)構(gòu)體 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
??????? 代碼有點問題就是模塊注銷的時候不能釋放中斷號,中斷組不能用,目前正在找原因。有知道原因的朋友可以告訴我下,謝謝