ckfwq/linux-3.0.4/drivers/char/gsc3280_gpioparal.c

314 lines
7.9 KiB
C

/*
* gsc3280_gpioparal.c - driver for Gpio Test
* 8bits out, 4bits in
*
* Copyright (C) 2012 Loongson Corporation
*
* 2013-03-15
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/rcupdate.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/completion.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <gsc3280/gpio.h>
#include <gsc3280/sysctl.h>
#include "gsc3280_gpioparal.h"
/*----------------------------------------------------------------------------*/
enum {
OUT_DAT0 = 0,
OUT_DAT1,
OUT_DAT2,
OUT_DAT3,
OUT_DAT4,
OUT_DAT5,
OUT_DAT6,
OUT_DAT7,
OUT_PIN_NR,
};
enum {
IN_DAT0 = 0,
IN_DAT1,
IN_DAT2,
IN_DAT3,
IN_PIN_NR
};
enum {
SWITCH_PIN = 0,
CTRL_PIN_NR
};
struct gpio out_gpios[OUT_PIN_NR] = {
{GSC3280_GPB(30), GPIOF_OUT_INIT_HIGH, "OUT_DAT0"},
{GSC3280_GPA(12), GPIOF_OUT_INIT_HIGH, "OUT_DAT1"},
{GSC3280_GPA(10), GPIOF_OUT_INIT_HIGH, "OUT_DAT2"},
{GSC3280_GPA(11), GPIOF_OUT_INIT_HIGH, "OUT_DAT3"},
{GSC3280_GPA(19), GPIOF_OUT_INIT_HIGH, "OUT_DAT4"},
{GSC3280_GPA(20), GPIOF_OUT_INIT_HIGH, "OUT_DAT5"},
{GSC3280_GPA(22), GPIOF_OUT_INIT_HIGH, "OUT_DAT6"},
{GSC3280_GPA(9), GPIOF_OUT_INIT_HIGH, "OUT_DAT7"}
};
struct gpio in_gpios[IN_PIN_NR] = {
{GSC3280_GPA(19), GPIOF_IN, "IN_DAT0"},
{GSC3280_GPA(20), GPIOF_IN, "IN_DAT1"},
{GSC3280_GPC(2), GPIOF_IN, "IN_DAT2"},
{GSC3280_GPC(0), GPIOF_IN, "IN_DAT3"}
};
struct gpio ctl_gpios[CTRL_PIN_NR] = {
{GSC3280_GPC(1), GPIOF_OUT_INIT_HIGH, "CTL_DAT0"}
};
/*----------------------------------------------------------------------------*/
struct gsc3280_gpioparal {
struct cdev cdev;
struct class *gpioparal_class;
bool out_gpios_init;
bool in_gpios_init;
dev_t dev;
};
struct gsc3280_gpioparal gpioparal_priv;
/*----------------------------------------------------------------------------*/
/* */
static ssize_t gpioparal_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos) {
return 0;
}
/*----------------------------------------------------------------------------*/
/* */
static ssize_t gpioparal_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos) {
return 0;
}
void gpio_paral_out_8bits(unsigned char val)
{
int i;
for (i = 0; i < OUT_PIN_NR; i++) {
gpio_set_value(out_gpios[i].gpio, (val >> i) & 0x01);
}
return;
}
unsigned char gpio_paral_in_8bits(void)
{
int i;
unsigned char val = 0;
gpio_set_value(ctl_gpios[SWITCH_PIN].gpio, 1);
udelay(1000);
for (i = 0; i < IN_PIN_NR; i++) {
val |= ((gpio_get_value(in_gpios[IN_PIN_NR - i - 1].gpio) & 0x01) << i);
}
gpio_set_value(ctl_gpios[SWITCH_PIN].gpio, 0);
udelay(1000);
for (i = 0; i < IN_PIN_NR; i++) {
val |= ((gpio_get_value(in_gpios[IN_PIN_NR - i - 1].gpio) & 0x01)
<< (i + IN_PIN_NR));
}
return val;
}
/*----------------------------------------------------------------------------*/
/* */
static long gpioparal_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int ret = 0;
unsigned char val = 0;
if (_IOC_TYPE(cmd) != GPIOPARAL_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > GPIOPARAL_IOC_MAXNR) return -ENOTTY;
switch(cmd) {
case GPIO_INIT_WRITE:
if (gpioparal_priv.out_gpios_init || gpioparal_priv.in_gpios_init)
break;
ret = gpio_request_array(out_gpios, OUT_PIN_NR);
if (ret < 0)
return ret;
gpioparal_priv.out_gpios_init = true;
break;
case GPIO_INIT_READ:
if (gpioparal_priv.out_gpios_init || gpioparal_priv.in_gpios_init)
break;
ret = gpio_request_array(in_gpios, IN_PIN_NR);
ret |= gpio_request_array(ctl_gpios, CTRL_PIN_NR);
if (ret < 0)
return ret;
gpioparal_priv.in_gpios_init = true;
break;
case GPIO_RELEASE_WRITE:
if (gpioparal_priv.out_gpios_init)
gpio_free_array(out_gpios, OUT_PIN_NR);
gpioparal_priv.out_gpios_init = false;
break;
case GPIO_RELEASE_READ:
if (gpioparal_priv.in_gpios_init) {
gpio_free_array(in_gpios, IN_PIN_NR);
gpio_free_array(ctl_gpios, CTRL_PIN_NR);
}
gpioparal_priv.in_gpios_init = false;
break;
case GPIO_PARAL_OUT:
if (arg) {
if (!gpioparal_priv.out_gpios_init)
return EPERM;
__get_user(val, (unsigned char*)arg);
gpio_paral_out_8bits(val);
}
break;
case GPIO_PARAL_IN:
if (arg) {
if (!gpioparal_priv.in_gpios_init)
return EPERM;
val = gpio_paral_in_8bits();
__put_user(val, (unsigned char*)arg);
}
break;
default:
return -ENOTTY;
}
return 0;
}
/*----------------------------------------------------------------------------*/
static int gpioparal_open(struct inode *inode, struct file *filp) {
return 0;
}
/*----------------------------------------------------------------------------*/
static int gpioparal_release(struct inode *inode, struct file *filp)
{
if (gpioparal_priv.out_gpios_init)
gpio_free_array(out_gpios, OUT_PIN_NR);
if (gpioparal_priv.in_gpios_init) {
gpio_free_array(in_gpios, IN_PIN_NR);
gpio_free_array(ctl_gpios, CTRL_PIN_NR);
}
gpioparal_priv.out_gpios_init = false;
gpioparal_priv.in_gpios_init = false;
return 0;
}
/*----------------------------------------------------------------------------*/
struct file_operations gpioparal_fops = {
.owner = THIS_MODULE,
.read = gpioparal_read,
.write = gpioparal_write,
.unlocked_ioctl = gpioparal_ioctl,
.open = gpioparal_open,
.release = gpioparal_release,
};
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static int __init gsc3280_gpioparal_init(void)
{
int err;
int result;
int major;
result = alloc_chrdev_region(&gpioparal_priv.dev, 0, 0, "gpioparal");
major = MAJOR(gpioparal_priv.dev);
if (result < 0) {
printk(KERN_WARNING "gpioparal: can't get major %d\n", major);
return result;
}
cdev_init(&gpioparal_priv.cdev, &gpioparal_fops);
gpioparal_priv.cdev.owner = THIS_MODULE;
gpioparal_priv.cdev.ops = &gpioparal_fops;
err = cdev_add(&gpioparal_priv.cdev, gpioparal_priv.dev, 1);
if (err) {
printk(KERN_NOTICE "Error[%d] cdev_add gpioparal\n", err);
return -1;
}
gpioparal_priv.gpioparal_class = class_create(THIS_MODULE,
"gsc3280_gpioparal");
if (IS_ERR(gpioparal_priv.gpioparal_class)) {
printk(KERN_ERR "Failed in create gpioparal class\n");
return -1;
}
device_create(gpioparal_priv.gpioparal_class, NULL,
gpioparal_priv.dev,
NULL, "gpioparal");
gpioparal_priv.out_gpios_init = false;
gpioparal_priv.in_gpios_init = false;
sysctl_iomux_disable(SYSCTL_IOMUX_SPI1);
return 0;
}
/*----------------------------------------------------------------------------*/
static void __exit gsc3280_gpioparal_exit(void)
{
cdev_del(&gpioparal_priv.cdev);
unregister_chrdev_region(gpioparal_priv.dev, 1);
device_destroy(gpioparal_priv.gpioparal_class, gpioparal_priv.dev);
class_destroy(gpioparal_priv.gpioparal_class);
}
/*----------------------------------------------------------------------------*/
module_init(gsc3280_gpioparal_init);
module_exit(gsc3280_gpioparal_exit);
/*----------------------------------------------------------------------------*/
MODULE_AUTHOR("ansonn.wang@gmail.com");
MODULE_DESCRIPTION("gsc3280 gpio parallel test<8bits <-> 4bits> driver");
MODULE_LICENSE("GPL");
/*----------------------------------------------------------------------------*/