drivers/char/atmel_sama5_gpio.c

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/module.h> 
#include <linux/init.h>
#include <linux/delay.h> 
#include <asm/irq.h> 
#include <mach/hardware.h> 
#include <linux/kernel.h> 
#include <linux/mm.h> 
#include <linux/fs.h> 
#include <linux/types.h> 
#include <linux/delay.h> 
#include <linux/slab.h> 
#include <linux/errno.h> 
#include <linux/ioctl.h> 
#include <linux/cdev.h> 
#include <asm/uaccess.h> 
#include <asm/atomic.h> 
#include <asm/unistd.h> 
#include <linux/platform_device.h>
#include <linux/io.h>
#include <mach/sama5d3.h>
#include <mach/gpio.h> 
#include <linux/gpio.h>
#include <asm/gpio.h>

#define GPIO_IOC_MAGIC					'G'
#define IOCTL_GPIO_SETOUTPUT			_IOW(GPIO_IOC_MAGIC, 0, int)                   
#define IOCTL_GPIO_SETINPUT				_IOW(GPIO_IOC_MAGIC, 1, int)
#define IOCTL_GPIO_SETVALUE				_IOW(GPIO_IOC_MAGIC, 2, int) 
#define IOCTL_GPIO_GETVALUE				_IOR(GPIO_IOC_MAGIC, 3, int)
#define GPIO_IOC_MAXNR					3

//#define AT91_PIN_1	AT91_PIN_PC18
typedef struct {
        int pin;
        int data;
        int usepullup;
}at91_gpio_arg;
 

static int gpio_major = 0;
static int gpio_minor = 0;
static struct class *gpio_class;
static struct class_device *class_dev;
static struct cdev gpio_cdev;

#define GPBR_DEBUG 0 
#if GPBR_DEBUG
#    define PDEBUG(fmt, args...) printk("atmel_gpio: " fmt, ## args)
#else
#  define PDEBUG(fmt, args...) 
#endif

/// GPIO 只有PC18 可用为普通IO口使用
static int gpio_open(struct inode *inode,struct file *filp)
{
	int rst;
///	rst = gpio_request(AT91_PIN_PB24, "atmel_gpio");
	return rst;
}

static int gpio_release(struct inode *inode,struct file *filp)
{
///	gpio_free(AT91_PIN_PB24);
	return 0;
}


static ssize_t gpio_read(struct file *filp, char __user *buf, size_t count,
                loff_t *f_pos)
{
	return 0;
}


ssize_t gpio_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
	return 0;
}


static loff_t gpio_llseek(struct file *filp, loff_t offset, int origin)
{
	return 0;
}

static long gpio_ioctl(struct file *filp,  unsigned int cmd,  unsigned long arg)
{
	int err = 0;

	at91_gpio_arg * parg = (at91_gpio_arg*) arg;  

	if (_IOC_TYPE(cmd) != GPIO_IOC_MAGIC) return -ENOTTY;
	if (_IOC_NR(cmd) > GPIO_IOC_MAXNR) return -ENOTTY;

	if (_IOC_DIR(cmd) & _IOC_READ)
		err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
	else if (_IOC_DIR(cmd) & _IOC_WRITE)
		err =  !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
	if (err) return -EFAULT;
	/// 对用户空间 限制使用GPIO(安全性)
/*	if (parg->pin != AT91_PIN_1) {
		printk(KERN_WARNING "This Pin Unsuported.\n");
		return -EFAULT;
	}
*/
	switch (cmd) {
	case IOCTL_GPIO_SETOUTPUT:
		err = gpio_request(parg->pin, "atmel_gpio");
		if(!err)
			gpio_direction_output(parg->pin, parg->data);
		break;	
		
	case IOCTL_GPIO_SETINPUT:
		err = gpio_request(parg->pin, "atmel_gpio");
		if(!err)
			gpio_direction_input(parg->pin);
		break;
	case IOCTL_GPIO_SETVALUE:
                err = gpio_request(parg->pin, "atmel_gpio");
                if(!err)
			gpio_set_value(parg->pin, parg->data);
		break;
	case IOCTL_GPIO_GETVALUE:
                err = gpio_request(parg->pin, "atmel_gpio");
                if(!err)
			parg->data = gpio_get_value(parg->pin) ? 1 : 0;
		break;
	default :
		printk(KERN_WARNING "Unsuported Ioctl Cmd\n");
	}
	
	if (!err) 
		gpio_free(parg->pin);
	return err;
}

struct file_operations gpio_fops = {
	.owner =    THIS_MODULE,
	.read =     gpio_read,
	.write =    gpio_write,
	.llseek =   gpio_llseek,
	.open =     gpio_open,
	.unlocked_ioctl =    gpio_ioctl,
	.release =  gpio_release,
};


static int __init sama5_gpio_init(void)
{
	int result;
	dev_t dev = 0;

	if (gpio_major) {
		dev = MKDEV(gpio_major, gpio_minor);
		result = register_chrdev_region(dev, 1, "atmel_gpio");
	} else {
		result = alloc_chrdev_region(&dev, gpio_minor, 1,
				"atmel_gpio");
		gpio_major = MAJOR(dev);
	}
	if (result < 0) {
		printk(KERN_WARNING "can't get major %d\n", gpio_major);
		return result;
	}

	cdev_init(&gpio_cdev, &gpio_fops);
	gpio_cdev.owner = THIS_MODULE;
	gpio_cdev.ops = &gpio_fops;
	result = cdev_add (&gpio_cdev, dev, 1);

	/// derves node file
	gpio_class = class_create(THIS_MODULE,"atmel_gpio");
	if (IS_ERR(gpio_class)) {
        	printk(KERN_WARNING "class_create faild\n");
		cdev_del(&gpio_cdev);
		unregister_chrdev_region(dev, 0);
		return result;
	}
	class_dev = device_create(gpio_class,NULL,dev,0,"atmel_gpio");
	return 0;
}

static void __exit sama5_gpio_exit(void)
{
	dev_t dev = 0;

	dev = MKDEV(gpio_major, gpio_minor);

	class_unregister(class_dev);
	class_destroy(gpio_class);
	unregister_chrdev_region(dev, 0); 
	cdev_del(&gpio_cdev);
}


module_init(sama5_gpio_init);

module_exit(sama5_gpio_exit);


MODULE_DESCRIPTION("Driver for a5d3 GPIO");
MODULE_AUTHOR("[email protected]");
MODULE_LICENSE("GPL");



猜你喜欢

转载自blog.csdn.net/qingzhuyuxian/article/details/81409774