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

241 lines
5.5 KiB
C

/*
* gsc3280_emidisp.c - driver for Emi Display in Loongson soc
*
* Copyright (C) 2012 Loongson Corporation
*
* 2013-01-31
*/
#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_emidisp.h"
/*----------------------------------------------------------------------------*/
enum {
EMI_LIGHG_PIN = 0,
RESET_PIN,
MAX_PIN_NR,
};
struct gpio emidsip_gpios[MAX_PIN_NR] = {
{gsc3280_GPA(0), GPIOF_OUT_INIT_HIGH, "emidisp_back_light"},
{gsc3280_GPA(1), GPIOF_OUT_INIT_HIGH, "emidisp_reset"}
};
#define EMI_DISP_GET_IOMUX() \
do {\
;\
} while (0)
#define EMI_DISP_RELEASE_IOMUX() \
do {\
;\
} while (0)
/*----------------------------------------------------------------------------*/
struct gsc3280_emidisp {
struct cdev cdev;
struct class *emidisp_class;
dev_t dev;
};
struct gsc3280_emidisp emidisp_priv;
/*----------------------------------------------------------------------------*/
static void emi_wr_dat(unsigned char uc_dat)
{
EMI_DISP_GET_IOMUX();
DAT_OPT = uc_dat;
EMI_DISP_RELEASE_IOMUX();
}
static void emi_wr_cmd(unsigned char uc_cmd)
{
EMI_DISP_GET_IOMUX();
CMD_OPT = uc_cmd;
EMI_DISP_RELEASE_IOMUX();
}
static void reset_emi_disp_dev(void)
{
//RST Set reset pin low sleep high
gpio_set_value(emidsip_gpios[RESET_PIN].gpio, 0);
udelay(1000);
gpio_set_value(emidsip_gpios[RESET_PIN].gpio, 1);
return;
}
static void emi_disp_back_light(unsigned char val)
{
gpio_set_value(emidsip_gpios[EMI_LIGHG_PIN].gpio, !!val);
}
/*----------------------------------------------------------------------------*/
/*
*/
static ssize_t emidisp_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos) {
return 0;
}
/*----------------------------------------------------------------------------*/
/*
*/
static ssize_t emidisp_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos) {
return 0;
}
/*----------------------------------------------------------------------------*/
/*
*/
static long emidisp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char val = 0;
if (_IOC_TYPE(cmd) != EMIDISP_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > EMIDISP_IOC_MAXNR) return -ENOTTY;
__get_user(val, (unsigned char*)arg);
switch(cmd) {
case EMIDISP_CMD:
if (arg)
emi_wr_cmd(val);
break;
case EMIDISP_DAT:
if (arg)
emi_wr_dat(val);
break;
case EMIDISP_RST:
reset_emi_disp_dev();
break;
case EMIDISP_BACK:
emi_disp_back_light(val);
break;
default:
return -ENOTTY;
}
return 0;
}
static int emidisp_open(struct inode *inode, struct file *filp) {
int ret = 0;
ret = gpio_request_array(emidsip_gpios,
sizeof(emidsip_gpios)/sizeof(emidsip_gpios[0]));
if (ret < 0)
return ret;
return 0;
}
static int emidisp_release(struct inode *inode, struct file *filp)
{
gpio_free_array(emidsip_gpios,
sizeof(emidsip_gpios)/sizeof(emidsip_gpios[0]));
return 0;
}
struct file_operations emidisp_fops = {
.owner = THIS_MODULE,
.read = emidisp_read,
.write = emidisp_write,
.unlocked_ioctl = emidisp_ioctl,
.open = emidisp_open,
.release = emidisp_release,
};
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static int __init gsc3280_emidisp_init(void)
{
int err;
int result;
int major;
result = alloc_chrdev_region(&emidisp_priv.dev, 0, 0, "emidisp");
major = MAJOR(emidisp_priv.dev);
if (result < 0) {
printk(KERN_WARNING "emidisp: can't get major %d\n", major);
return result;
}
cdev_init(&emidisp_priv.cdev, &emidisp_fops);
emidisp_priv.cdev.owner = THIS_MODULE;
emidisp_priv.cdev.ops = &emidisp_fops;
err = cdev_add(&emidisp_priv.cdev, emidisp_priv.dev, 1);
if (err) {
printk(KERN_NOTICE "Error[%d] cdev_add emidisp\n", err);
return -1;
}
emidisp_priv.emidisp_class = class_create(THIS_MODULE, "gsc3280_emidisp");
if (IS_ERR(emidisp_priv.emidisp_class)) {
printk(KERN_ERR "Failed in create gsc3280_cdev class\n");
return -1;
}
device_create(emidisp_priv.emidisp_class, NULL,
emidisp_priv.dev,
NULL, "emidisp");
return 0;
}
/*----------------------------------------------------------------------------*/
static void __exit gsc3280_emidisp_exit(void)
{
cdev_del(&emidisp_priv.cdev);
unregister_chrdev_region(emidisp_priv.dev, 1);
device_destroy(emidisp_priv.emidisp_class, emidisp_priv.dev);
class_destroy(emidisp_priv.emidisp_class);
}
/*----------------------------------------------------------------------------*/
module_init(gsc3280_emidisp_init);
module_exit(gsc3280_emidisp_exit);
/*----------------------------------------------------------------------------*/
MODULE_AUTHOR("ansonn.wang@gmail.com");
MODULE_DESCRIPTION("gsc3280 emi Display driver");
MODULE_LICENSE("GPL");
/*----------------------------------------------------------------------------*/