📄 at91_mygpio.c
字号:
/*====================================================================== current file::/drivers/at91/mygpio/at91_mygpio.c Device driver for the GPIO(PIO) control of Atmel AT91RM9200 (c)e-tek Ltd,Shenzhen,Guangdong,China The original code is created by beeswing<beeswing@21cn.com>. 20060216 add portb irq handle as a share read Copyright (C) 2005 beeswing. All Rights Reserved. ======================================================================*/ #include <linux/module.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/proc_fs.h>#include <linux/init.h>#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif#include <asm/io.h>#include <asm/arch/hardware.h>#include "at91_mygpio.h"///#define GPIO_DEBUG 1#define PORT(x) ((x >> 8) & 0x0F)#define GPIO(x) (x & 0xFF)#define PORT_MAX NR_GPIO_DEVICES#define GPIO_MAX 32extern AT91PS_SYS AT91_SYS;#ifdef CONFIG_PORTS_SHARE_IRQ unsigned long ports_irq_status[4]; static unsigned int port_dev_id[4]; #endif#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_handle = NULL;#endif//check if gpio or AB select function 1=gpiostatic int check_gpio_fun(AT91PS_PIO PORT, unsigned int num){ return (PORT->PIO_PSR & PIO_GPIO(num)) ? 1 : 0;}//check the direction: 1 = outputstatic int check_gpio_direct(AT91PS_PIO PORT, unsigned int num){ return (PORT->PIO_OSR & PIO_GPIO(num)) ? 1 : 0;}static ssize_t gpio_write(struct file * file, const char * buf, size_t count, loff_t * ppos){ unsigned int gpio_arg = file->private_data; unsigned int gpio_device = PORT(gpio_arg); unsigned int pin_num = GPIO(gpio_arg); AT91PS_PIO AT91_PORT = (AT91PS_PIO)(unsigned long)(AT91C_VA_BASE_SYS + 0x400 + 0x200 * gpio_device); if (gpio_device >= NR_GPIO_DEVICES) return -ENODEV; if (!check_gpio_fun(AT91_PORT, pin_num)) { printk(KERN_ERR "IO not a gpio!\n"); return -EIO; } if (!check_gpio_direct(AT91_PORT, pin_num)) { printk(KERN_ERR "Not a output gpio!\n"); return -EIO; }#ifdef GPIO_DEBUG printk("MYgpio write port %d pin %d:data %c!\n", gpio_device,pin_num,*buf);#endif if ( (*buf) == '1') AT91_PORT->PIO_SODR = PIO_GPIO(pin_num); else if ( (*buf) == '0') AT91_PORT->PIO_CODR = PIO_GPIO(pin_num); return 1;}//static ssize_t gpio_read (struct file * file, char * buf, size_t count, loff_t * ppos) { unsigned int gpio_arg = file->private_data; unsigned int gpio_device = PORT(gpio_arg); unsigned int pin_num = GPIO(gpio_arg); AT91PS_PIO AT91_PORT = (AT91PS_PIO)(unsigned long)(AT91C_VA_BASE_SYS + 0x400 + 0x200 * gpio_device); if (gpio_device >= NR_GPIO_DEVICES) return -ENODEV; if (!check_gpio_fun(AT91_PORT, pin_num)) { printk(KERN_ERR "IO not a gpio!\n"); return -EIO; } if (check_gpio_direct(AT91_PORT, pin_num)) { printk(KERN_ERR "Not a input gpio!\n"); return -EIO; } *buf = (AT91_PORT->PIO_PDSR & PIO_GPIO(pin_num))? '1':'0'; #ifdef GPIO_DEBUG printk("MYgpio read port %d pin %d data:%c!\n",gpio_device, pin_num, *buf);#endif return 1;}//arg include input pin_numstatic int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned int gpio_device = MINOR(inode->i_rdev); unsigned int pin_num = GPIO(arg); AT91PS_PIO AT91_PORT = (AT91PS_PIO)(unsigned long)(AT91C_VA_BASE_SYS + 0x400 + 0x200 * gpio_device); if (gpio_device >= NR_GPIO_DEVICES) return -ENODEV;#ifdef MYGPIO_DEBUG printk(KERN_INFO "mygpio minor: %X \n",gpio_device);#endif if (pin_num > GPIO_MAX) { printk(KERN_ERR "mygpio IO error in ioctl!\n"); return -EIO; } #ifdef MYGPIO_DEBUG printk(KERN_INFO "mygpio pin NO: %d\n",pin_num);#endif //map physical address this method is OK //move to open function ///AT91_PORT = (AT91PS_PIO)(unsigned long)(AT91C_VA_BASE_SYS + 0x400 + 0x200 * gpio_device);#ifdef MYGPIO_DEBUG printk("mygpio ioctl setting cmd:%X Arg: %X port_base: %X \n",cmd,arg,AT91_PORT);#endif switch (cmd) { case PIO_SET_PASR: AT91_PORT->PIO_ASR = PIO_GPIO(pin_num); AT91_PORT->PIO_PDR = PIO_GPIO(pin_num); break; case PIO_SET_PBSR: AT91_PORT->PIO_BSR = PIO_GPIO(pin_num); AT91_PORT->PIO_PDR = PIO_GPIO(pin_num); break; case PIO_SET_GPIO: AT91_PORT->PIO_PER = PIO_GPIO(pin_num); break; case PIO_SET_INPUT: AT91_PORT->PIO_ODR = PIO_GPIO(pin_num); break; case PIO_SET_OUTPUT: AT91_PORT->PIO_OER = PIO_GPIO(pin_num); break; default: return -EINVAL; } (unsigned int) file->private_data = (gpio_device << 8) | pin_num; return 0;}static int gpio_open(struct inode *inode, struct file *file){ unsigned int gpio_device = MINOR(inode->i_rdev); //move from ioctl AT91PS_PIO AT91_PORT = (AT91PS_PIO)(unsigned long)(AT91C_VA_BASE_SYS + 0x400 + 0x200 * gpio_device); if (gpio_device >= NR_GPIO_DEVICES) return -ENODEV; MOD_INC_USE_COUNT; AT91_SYS->PMC_PCER = 1 << (AT91C_ID_PIOA + gpio_device); #ifdef GPIO_DEBUG printk(KERN_INFO "mygpio open port %d add:%X \n", gpio_device,AT91_PORT);#endif return 0;}static int gpio_close(struct inode *inode, struct file *file){ unsigned int gpio_device = MINOR(inode->i_rdev); if (gpio_device >= NR_GPIO_DEVICES) return -ENODEV; //disable peripheral clock AT91_SYS->PMC_PCDR = 1 << (AT91C_ID_PIOA + gpio_device); MOD_DEC_USE_COUNT;#ifdef GPIO_DEBUG printk(KERN_INFO "mygpio close port %d add:%X \n", gpio_device,AT91_PORT);#endif return 0;}#ifdef CONFIG_PORTS_SHARE_IRQstatic void port_interrupt_handle(int irq, void *dev_id, struct pt_regs *regs){ AT91PS_PIO at91_gport = (AT91PS_PIO)(unsigned long)(AT91C_VA_BASE_SYS + 0x400 + 0x200 * (irq - AT91C_ID_PIOA)); ports_irq_status[irq - AT91C_ID_PIOA] = at91_gport->PIO_ISR & at91_gport->PIO_IMR; //printk("mygpio.c port(%d) irq status = %X\n", irq - AT91C_ID_PIOA, ports_irq_status[irq - AT91C_ID_PIOA]);}#endif//file operationsstatic struct file_operations gpio_fops = { owner: THIS_MODULE, read: gpio_read, write: gpio_write, ioctl: gpio_ioctl, open: gpio_open, release: gpio_close,};/* * Main initialization routine */static int __init init_gpio(void){ unsigned int i;#ifdef CONFIG_DEVFS_FS unsigned char *devname; if (devfs_register_chrdev(GPIO_MAJOR, "mygpio", &gpio_fops)) {#else if (register_chrdev(GPIO_MAJOR, "mygpio", &gpio_fops)) {#endif printk(KERN_ERR "mygpio: unable to get major %d\n", GPIO_MAJOR); return -EIO; } #ifdef CONFIG_DEVFS_FS devfs_handle = devfs_mk_dir(NULL, "mygpio", NULL); if (!devfs_handle) return -EBUSY; devfs_register_series (devfs_handle, "port%u", NR_GPIO_DEVICES, \ DEVFS_FL_DEFAULT, \ GPIO_MAJOR, 0, S_IFCHR | S_IRUGO | S_IWUGO, \ &gpio_fops, NULL);#endif#ifdef CONFIG_PORTS_SHARE_IRQ for (i = 0; i < PORTS_NUM; i++){ if (request_irq(AT91C_ID_PIOA + i, port_interrupt_handle, SA_SHIRQ, "mygpio", &port_dev_id[i])){ printk(KERN_ERR "can not get assigned ports irq %d\n", AT91C_ID_PIOA+i); } }#endif printk(KERN_INFO "mygpio driver initialized by beeswing!\n"); return 0;}static void __exit gpio_cleanup(void){#ifdef CONFIG_PORTS_SHARE_IRQ int i; for (i = 0; i < PORTS_NUM; i++){ free_irq(AT91C_ID_PIOA + i, &port_dev_id[i]); }#endif#ifdef CONFIG_DEVFS_FS devfs_unregister(devfs_handle); if (devfs_unregister_chrdev(GPIO_MAJOR, "mygpio"))#else if (unregister_chrdev(GPIO_MAJOR, "mygpio"))#endif printk(KERN_ERR "at91_mygpio: Unable to release major %d for gpio\n", GPIO_MAJOR); return;}EXPORT_NO_SYMBOLS;MODULE_AUTHOR("Beeswing");MODULE_DESCRIPTION("GPIO driver for Atmel AT91RM9200");MODULE_LICENSE("GPL");module_init(init_gpio);module_exit(gpio_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -