#include <linux/module.h>  
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/uio_driver.h>
#include <linux/platform_device.h>

#define GPIOBAdr 0x56000014

#define DRV_NAME "JoeyLED"
#define DRV_VERSION "0.0.1"


static irqreturn_t led_handler(int irq, struct uio_info *dev_info)
{
	printk("interrupt happened\n");
	return IRQ_HANDLED;
}

static int __init led_probe(struct platform_device *dev)
{
	struct resource *regs;
	struct uio_info *info;
	
	printk("probing led\n");
	info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;
	regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
	if (!regs) 
	{
		dev_err(&dev->dev, "No memory resource specified\n");
		return -ENODEV;
	}else
	{
		printk("GPIOB reg->start %x reg->end %x \n",regs->start,regs->end );
	}
	info->mem[0].addr = regs->start;
	info->mem[0].size=regs->end - regs->start;
	info->mem[0].internal_addr=ioremap(regs->start, info->mem[0].size);;
	if (!info->mem[0].addr) 
	{
		dev_err(&dev->dev, "Invalid memory resource\n");
		return -ENODEV;
	}
	
	info->mem[0].memtype = UIO_MEM_PHYS;
	info->version = "0.0.1";
	info->name="JoeyLED";
	info->irq=platform_get_irq(dev, 0);
	info->irq_flags = IRQF_SHARED;
	info->handler = led_handler;
	if (uio_register_device(&dev->dev, info))
	{
		iounmap(info->mem[0].internal_addr);
		printk("uio_register failed\n");
		return -ENODEV;
	}
	platform_set_drvdata(dev, info); 
	printk("probing led success\n");
	return 0;
}

static int __exit led_remove(struct platform_device *dev)
{
	struct uio_info *info = platform_get_drvdata(dev);
	
	uio_unregister_device(info);
	platform_set_drvdata(dev, NULL);
	iounmap(info->mem[0].internal_addr);
	kfree(info);
	return 0;
}

static struct platform_driver led_driver = {
	.probe		= led_probe,
	.remove		= __devexit_p(led_remove),
	.driver		= {
		.name	= DRV_NAME,
		.owner	= THIS_MODULE,
	},
};

static int __init led_init(void)
{
	printk("QT2410 LED driver demo\n");
	
	return platform_driver_register(&led_driver);
}

static void __exit led_exit(void)
{
	platform_driver_unregister(&led_driver);
}
module_init(led_init);
module_exit(led_exit);

MODULE_DESCRIPTION("led module");
MODULE_AUTHOR("Joey Cheng<jemicheng@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("QT2410:LED module");
