/*
* 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");
drivers/char/atmel_sama5_gpio.c
猜你喜欢
转载自blog.csdn.net/qingzhuyuxian/article/details/81409774
今日推荐
周排行