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

415 lines
9.6 KiB
C

/*
* gsc3280_gpodisp.c - driver for Gpo 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 "gsc3280_gpodisp.h"
void gpio_nand_lock(void);
void gpio_nand_unlock(void);
#define GPODISP_GET_IOMUX_LOCK() \
do {\
gpio_nand_lock();\
} while (0)
#define GPODISP_PUT_IOMUX_LOCK() \
do {\
gpio_nand_unlock();\
} while (0)
/*----------------------------------------------------------------------------*/
struct gsc3280_gpodisp {
struct cdev cdev;
struct class *gpodisp_class;
dev_t dev;
bool display_init;
};
struct gsc3280_gpodisp gpodisp_priv;
unsigned char disp_mem[108][160];
/*----------------------------------------------------------------------------*/
static void gpo_wr_dat(unsigned char uc_dat)
{
u32 reg_val = 0;
u32 dat_val = (u32)uc_dat;
/*
A0 -> GPIO26
CS -> GPIO62
RST -> GPIO87
RD -> GPIO35
WD -> GPIO36
DAT -> GPIP38~45
conflict module -> spi0;keypad;emi;iis;pwm
*/
/* RD set 1 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val |= (0x01 << 3);
*((volatile u32 *)0xbc11000c) = reg_val;
/* A0 set 1 */
reg_val = *((volatile u32 *)0xbc110000);
reg_val |= (0x01 << 26);
*((volatile u32 *)0xbc110000) = reg_val;
/* CS set 0 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val &= ~(0x01 << 30);
*((volatile u32 *)0xbc11000c) = reg_val;
/* WD set 0 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val &= ~(0x01 << 4);
*((volatile u32 *)0xbc11000c) = reg_val;
/* uc_dat >> data0~7 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val &= ~(0xff << 6);
reg_val |= (dat_val << 6);
*((volatile u32 *)0xbc11000c) = reg_val;
/* WD set 1 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val |= (0x01 << 4);
*((volatile u32 *)0xbc11000c) = reg_val;
/* CS set 1 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val |= (0x01 << 30);
*((volatile u32 *)0xbc11000c) = reg_val;
}
static void gpo_wr_cmd(unsigned char uc_cmd)
{
u32 reg_val = 0;
volatile u32 cmd_val = (u32)uc_cmd;
/*
A0 -> GPIO26
CS -> GPIO62
RST -> GPIO87
RD -> GPIO35
WD -> GPIO36
DAT -> GPIP38~45
conflict module -> spi0;keypad;emi;iis;pwm
*/
/* RD set 1 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val |= (0x01 << 3);
*((volatile u32 *)0xbc11000c) = reg_val;
/* A0 set 0 */
reg_val = *((volatile u32 *)0xbc110000);
reg_val &= ~(0x01 << 26);
*((volatile u32 *)0xbc110000) = reg_val;
/* CS set 0 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val &= ~(0x01 << 30);
*((volatile u32 *)0xbc11000c) = reg_val;
/* WD set 0 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val &= ~(0x01 << 4);
*((volatile u32 *)0xbc11000c) = reg_val;
/* uc_dat >> data0~7 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val &= ~(0xff << 6);
reg_val |= (cmd_val << 6);
*((u32 *)0xbc11000c) = reg_val;
/* WD set 1 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val |= (0x01 << 4);
*((volatile u32 *)0xbc11000c) = reg_val;
/* CS set 1 */
reg_val = *((volatile u32 *)0xbc11000c);
reg_val |= (0x01 << 30);
*((volatile u32 *)0xbc11000c) = reg_val;
}
static void enable_gpo_disp_pin(void)
{
/*
A0 -> GPIO26
CS -> GPIO83
RST -> GPIO87
DAT -> GPIP38~45
conflict module -> spi0;keypad;emi;iis;pwm
*/
/* not support hw src */
*((u32 *)0xbc110008) = 0;
*((u32 *)0xbc110014) = 0;
*((u32 *)0xbc110020) = 0;
/* set gpioABC output */
*((u32 *)0xbc110004) = 0x4000000;
*((u32 *)0xbc110010) = 0x40003fd8;
*((u32 *)0xbc11001c) = 0x800000;
}
static void reset_gpo_disp_dev(void)
{
//RST -> GPIO87
u32 reg_val = 0;
reg_val = *((u32 *)0xbc110018);
reg_val &= ~(0x01 << 23);
*((u32 *)0xbc110018) = reg_val;
udelay(1000);
reg_val = *((u32 *)0xbc110018);
reg_val |= (0x01 << 23);
*((u32 *)0xbc110018) = reg_val;
udelay(1000);
}
static void gpo_disp_ctrl_init(void)
{
gpo_wr_cmd(0xE2); //System Reset
udelay(100000);
gpo_wr_cmd(0xAE); //Set Display Disable
gpo_wr_cmd(0x25); //Set Temperature Compensation (00-0.00%)
gpo_wr_cmd(0x2B); //Set Power Control (Interal VLCD;Panel loading definition>13nF)
gpo_wr_cmd(0xE9); //Set LCD Bias ratio:1/10
gpo_wr_cmd(0x81); //Set gain and potentiometer Mode
gpo_wr_cmd(0xC0); //Program Gain:01;PM value:xx
gpo_wr_cmd(0x89); //Set RAM Address Control
gpo_wr_cmd(0xC4); //Set LCD Maping Control (MY=1, MX=0)
gpo_wr_cmd(0xDE); //Set COM Scan Function
gpo_wr_cmd(0xC8); //Set N-Line Inversion
gpo_wr_cmd(0x18); //Set COM Scan Function
gpo_wr_cmd(0xA3); //Set Line Rate
gpo_wr_cmd(0xD6); //Set Color Mode (64K)
gpo_wr_cmd(0xD1); //Set Color Pattern (RGB)
gpo_wr_cmd(0x84); //Set Partial Display Off
gpo_wr_cmd(0xAD); //Set Display Enable
gpodisp_priv.display_init = true;
}
/*---------------------------------------------------------------------------*/
/*
*/
static ssize_t gpodisp_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
unsigned char uc_RowCnt, uc_ColCnt;
unsigned char uc_RowAddrH, uc_RowAddrL;
if (sizeof(disp_mem) > count)
return -EFAULT;
if (copy_from_user(disp_mem, buf, count))
return -EFAULT;
if (gpodisp_priv.display_init == false)
gpo_disp_ctrl_init();
for (uc_RowCnt = 0; uc_RowCnt < 160; uc_RowCnt++)
{
uc_RowAddrH = uc_RowCnt / 16;
uc_RowAddrL = uc_RowCnt % 16;
gpo_wr_cmd(0x70 | uc_RowAddrH); //Set Row Address(MSB)
gpo_wr_cmd(0x60 | uc_RowAddrL); //Set Row Address(LSB)
gpo_wr_cmd(0x12); //Set Address(MSB)
gpo_wr_cmd(0x05); //Set Address(LSB)
for (uc_ColCnt = 0; uc_ColCnt < 108; uc_ColCnt++)
{
gpo_wr_dat(disp_mem[uc_ColCnt][uc_RowCnt]);
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*
*/
static ssize_t gpodisp_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
return 0;
}
/*----------------------------------------------------------------------------*/
/*
*/
static long gpodisp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char val = 0;
if (_IOC_TYPE(cmd) != GPODISP_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > GPODISP_IOC_MAXNR) return -ENOTTY;
__get_user(val, (unsigned char*)arg);
GPODISP_GET_IOMUX_LOCK();
switch(cmd) {
case GPODISP_CMD:
if (arg) {
gpo_wr_cmd(val);
}
break;
case GPODISP_DAT:
if (arg) {
gpo_wr_dat(val);
}
break;
case GPODISP_RST:
reset_gpo_disp_dev();
break;
case GPODISP_INITPIN:
enable_gpo_disp_pin();
break;
case GPODISPLAY_CTRL_INIT:
gpo_disp_ctrl_init();
break;
case GPODISPLAY_CTRL_BACKLIGHT:
printk(KERN_ERR "No Ctrl Pin define!");
break;
default:
return -ENOTTY;
}
GPODISP_PUT_IOMUX_LOCK();
return 0;
}
static int gpodisp_open(struct inode *inode, struct file *filp)
{
enable_gpo_disp_pin();
reset_gpo_disp_dev();
gpo_disp_ctrl_init();
return 0;
}
static int gpodisp_release(struct inode *inode, struct file *filp)
{
return 0;
}
struct file_operations gpodisp_fops = {
.owner = THIS_MODULE,
.read = gpodisp_read,
.write = gpodisp_write,
.unlocked_ioctl = gpodisp_ioctl,
.open = gpodisp_open,
.release = gpodisp_release,
};
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static int __init gsc3280_gpodisp_init(void)
{
int err;
int result;
int major;
result = alloc_chrdev_region(&gpodisp_priv.dev, 0, 0, "gpodisp");
major = MAJOR(gpodisp_priv.dev);
if (result < 0) {
printk(KERN_WARNING "gpodisp: can't get major %d\n", major);
return result;
}
cdev_init(&gpodisp_priv.cdev, &gpodisp_fops);
gpodisp_priv.cdev.owner = THIS_MODULE;
gpodisp_priv.cdev.ops = &gpodisp_fops;
err = cdev_add(&gpodisp_priv.cdev, gpodisp_priv.dev, 1);
if (err) {
printk(KERN_NOTICE "Error[%d] cdev_add gpodisp\n", err);
return -1;
}
gpodisp_priv.gpodisp_class = class_create(THIS_MODULE, "gsc3280_gpodisp");
if (IS_ERR(gpodisp_priv.gpodisp_class)) {
printk(KERN_ERR "Failed in create gsc3280_cdev class\n");
return -1;
}
device_create(gpodisp_priv.gpodisp_class, NULL,
gpodisp_priv.dev,
NULL, "gpodisp");
gpodisp_priv.display_init = false;
return 0;
}
/*----------------------------------------------------------------------------*/
static void __exit gsc3280_gpodisp_exit(void)
{
cdev_del(&gpodisp_priv.cdev);
unregister_chrdev_region(gpodisp_priv.dev, 1);
device_destroy(gpodisp_priv.gpodisp_class, gpodisp_priv.dev);
class_destroy(gpodisp_priv.gpodisp_class);
}
/*----------------------------------------------------------------------------*/
module_init(gsc3280_gpodisp_init);
module_exit(gsc3280_gpodisp_exit);
/*----------------------------------------------------------------------------*/
MODULE_AUTHOR("ansonn.wang@gmail.com");
MODULE_DESCRIPTION("gsc3280 Gpo Display driver");
MODULE_LICENSE("GPL");
/*----------------------------------------------------------------------------*/