#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define __devinit
#define __devexit
#define __devinitdata
#define DRIVER_NAME "KEY"
MODULE_AUTHOR("Pingbo An");
MODULE_LICENSE("GPL v2");
struct key_dev{
struct cdev dev;
struct work_struct work;
int irq;
int major;
unsigned long start_addr;
unsigned long size;
void __iomem *baseaddr;
int width;
int inout;
int key_prs;
};
static DECLARE_WAIT_QUEUE_HEAD(press_queue);
static volatile int event_press=0;
static irqreturn_t key_interrupt(int irq, void *dev_id)
{
struct key_dev *dev=dev_id;
dev->key_prs++;
printk(KERN_INFO "interruptted\n");
//schedule_work(&dev->work);
event_press=1;
wake_up_interruptible(&press_queue);
return IRQ_HANDLED;
}
/*
void irq_work_handle(struct work_struct *work)
{
struct key_dev *k_dev=container_of(work, struct key_dev, work);
k_dev->key_prs++;
printk(KERN_INFO "recived interrupt\n");
event_press=1;
wake_up_interruptible(&press_queue);
}
*/
static int key_open(struct inode *inode, struct file *filp)
{
struct key_dev *k_dev;
struct resource *res;
int err;
int gpio_reg;
int intr_reg;
printk(KERN_INFO "open device\n");
k_dev=container_of(inode->i_cdev, struct key_dev, dev);
filp->private_data=k_dev;
res=request_mem_region(k_dev->start_addr, k_dev->size, DRIVER_NAME);
if(!res){
printk("ERROR: cannot request mem\n");
return 0;
}
k_dev->baseaddr=ioremap(k_dev->start_addr, k_dev->size);
if(!(k_dev->baseaddr)){
printk("ERROR: cannot remap addr\n");
return 0;
}
if(k_dev->inout==0)
iowrite32(0,k_dev->baseaddr+4);//output
else
iowrite32(0xFFFFFFFF, k_dev->baseaddr+4);//input
err=request_irq(k_dev->irq, key_interrupt, IRQF_SHARED|IRQF_TRIGGER_RISING, DRIVER_NAME, k_dev);
if(err){
printk("ERROR: cannot request interrupt err = %d\n", err);
return 0;
}
//INIT_WORK(&k_dev->work, irq_work_handle);
gpio_reg=ioread32(k_dev->baseaddr+4);
iowrite32(gpio_reg|0xF, k_dev->baseaddr+4);
intr_reg=ioread32(k_dev->baseaddr+0x128);
iowrite32(intr_reg | 0x01, k_dev->baseaddr+0x128);//enable interrupt
iowrite32(0x80000000, k_dev->baseaddr+0x11C);
k_dev->key_prs=0;
printk(KERN_INFO "have open the key device\n");
return 0;
}
static int key_close(struct inode *inode, struct file *filp)
{
struct key_dev *dev=(struct key_dev*)filp->private_data;
int intr_reg=ioread32(dev->baseaddr+0x128);
iowrite32(intr_reg&0xFFFFFFF0, dev->baseaddr+0x128);
iounmap(dev->baseaddr);
free_irq(dev->irq, dev);
release_mem_region(dev->start_addr, dev->size);
return 0;
}
ssize_t key_read(struct file *filp, char __user *buf, size_t count, loff_t *fops)
{
int err;
struct key_dev *dev=filp->private_data;
wait_event_interruptible(press_queue, event_press);
event_press=0;
err=copy_to_user(buf, &dev->key_prs, count);
return err ? -EFAULT : 0;
}
struct file_operations key_fops={
.owner=THIS_MODULE,
.open=key_open,
.read=key_read,
.release=key_close,
};
static int key_cdev_init(struct key_dev *lp)
{
dev_t devno;
int rc;
rc=alloc_chrdev_region(&devno, 0, 1, DRIVER_NAME);
lp->major=MAJOR(devno);
if(rc<0){
printk(KERN_WARNING "cannot allocate chardev region\n");
return rc;
}
cdev_init(&lp->dev, &key_fops);
lp->dev.owner=THIS_MODULE;
lp->dev.ops=&key_fops;
rc=cdev_add(&lp->dev, devno, 1);
if(rc<0){
printk(KERN_ERR "cannot add device\n");
goto error;
}
return 0;
error:
unregister_chrdev_region(MKDEV(lp->major, 0), 1);
return -1;
}
static void key_cdev_free(struct key_dev *lp)
{
dev_t devno=MKDEV(lp->major, 0);
cdev_del(&lp->dev);
unregister_chrdev_region(devno, 1);
}
static int __devinit key_probe(struct platform_device *pdev)
{
struct device_node *node;
struct resource *mem;
unsigned int r_irq;
struct key_dev *lp=NULL;
struct device *dev=&pdev->dev;
int width;
int input, output, inout;
node=dev->of_node;
mem=platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(!mem){
printk(KERN_ERR "get memory resource\n");
return -ENODEV;
}
r_irq=irq_of_parse_and_map(node, 0);
if(!r_irq){
printk(KERN_ERR "get interrupt\n");
}
printk(KERN_INFO "irq number is %d", r_irq);
if(of_property_read_u32(node, "xlnx,gpio-width", &width)){
printk(KERN_ERR "get the gpio-width\n");
}
if(of_property_read_u32(node, "xlnx,all-inputs", &input)){
printk(KERN_ERR "get gpio inputs");
}
if(of_property_read_u32(node, "xlnx,all-outputs", &output)){
printk(KERN_ERR "get gpio outputs");
}
if(input == 1){
inout = 1;
}
else{
inout = 0;
}
lp=(struct key_dev *)kzalloc(sizeof(struct key_dev), GFP_KERNEL);
if(!lp){
printk(KERN_ERR "cannot allocate the key_dev\n");
return -ENOMEM;
}
printk(KERN_INFO "mem is %x", mem->start);
printk(KERN_INFO "width is %d", width);
lp->start_addr=mem->start;
lp->size=mem->end-mem->start;
lp->irq=r_irq;
lp->width=width;
dev_set_drvdata(dev, lp);
key_cdev_init(lp);
printk(KERN_INFO "succeed to probe and register key device\n");
return 0;
}
static int __devexit key_remove(struct platform_device *pdev)
{
struct device *dev=&pdev->dev;
struct key_dev *lp=dev_get_drvdata(dev);
key_cdev_free(lp);
kfree(lp);
dev_set_drvdata(dev, NULL);
return 0;
}
static const struct of_device_id key_of_match[] __devinitdata={
{.compatible="xlnx,gpio-keys",},
{/*end of list*/},
};
MODULE_DEVICE_TABLE(of, key_of_match);
static struct platform_driver key_driver={
.driver={
.name=DRIVER_NAME,
.owner=THIS_MODULE,
.of_match_table=key_of_match,
},
.probe=key_probe,
.remove=key_remove,
};
static int __init keys_init(void)
{
printk(KERN_INFO "start key gpio\n");
return platform_driver_register(&key_driver);
}
static void __exit keys_exit(void)
{
platform_driver_unregister(&key_driver);
printk(KERN_INFO "end key gpio\n");
}
module_init(keys_init);
module_exit(keys_exit);