zynq上LED驱动编写

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/anpingbo/article/details/84890144
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include<linux/types.h>
#include <linux/miscdevice.h>
#include <linux/irq.h>
#include <linux/of_irq.h>

#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);












猜你喜欢

转载自blog.csdn.net/anpingbo/article/details/84890144
今日推荐