349 lines
9.7 KiB
C
349 lines
9.7 KiB
C
/*
|
|
eeprom.c - Part of lm_sensors, Linux kernel modules for hardware
|
|
monitoring
|
|
Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
|
|
Philip Edelbrock <phil@netroedge.com>
|
|
Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
|
|
Copyright (C) 2003 IBM Corp.
|
|
|
|
2004-01-16 Jean Delvare <khali@linux-fr.org>
|
|
Divide the eeprom in 32-byte (arbitrary) slices. This significantly
|
|
speeds sensors up, as well as various scripts using the eeprom
|
|
module.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/mutex.h>
|
|
#include<linux/delay.h>
|
|
#include "../../input/touchscreen/s3c_ts_iic.h"
|
|
//Ivan 20090608 Ivan
|
|
#define ROTATE_NAGATIVE_90
|
|
//Ivan 20090608 Ivan
|
|
//Tony test
|
|
//#define QISDA_TEST_GPIO_PROBE
|
|
|
|
#include <asm/io.h>
|
|
|
|
/*kit.mod 20090811*/
|
|
#include "../../video/epaper.h"
|
|
/*kit.end*/
|
|
|
|
/* Addresses to scan */
|
|
|
|
#define QISDA_IIC_ID 0xB8
|
|
#define DELAY_TIME_IIC_READ 8//1//8
|
|
static struct i2c_driver qisda_iic_driver;
|
|
static unsigned short normal_i2c[] = { QISDA_IIC_ID>>1 , I2C_CLIENT_END };
|
|
I2C_CLIENT_INSMOD_1(qisda_iic);
|
|
|
|
typedef struct qisda_iic_data{
|
|
struct i2c_client client;
|
|
struct mutex update_lock;
|
|
u8 valid; /* bitfield, bit!=0 if slice is valid */
|
|
unsigned long last_updated[8]; /* In jiffies, 8 slices */
|
|
};
|
|
|
|
typedef struct {
|
|
unsigned char subaddr;
|
|
unsigned char value;
|
|
}qisda_iic_t;
|
|
|
|
qisda_iic_t qisda_iics_regs_mirror[2]=
|
|
{
|
|
{0x40,0xff},
|
|
{0x41,0xff},
|
|
};
|
|
|
|
static int qisda_iic_attach_adapter(struct i2c_adapter *adapter);
|
|
static int qisda_iic_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
static int qisda_iic_detach_client(struct i2c_client *client);
|
|
unsigned char qisda_iic_read(struct i2c_client *client, unsigned char subaddr);
|
|
static int qisda_iic_write(struct i2c_client *client, unsigned char subaddr, unsigned char val);
|
|
static int qisda_iic_command(struct i2c_client *client, unsigned int cmd, void *arg);
|
|
|
|
|
|
//Tony test
|
|
#ifdef QISDA_TEST_GPIO_PROBE
|
|
static void __iomem *g_pGPIOReg_GPFCON;
|
|
#endif
|
|
|
|
/* This is the driver that will be inserted */
|
|
static struct i2c_driver qisda_iic_driver = {
|
|
.driver = {
|
|
.name = "qisda_iic",
|
|
},
|
|
.id = I2C_DRIVERID_QISDA_AUO,
|
|
.attach_adapter = qisda_iic_attach_adapter,
|
|
.detach_client = qisda_iic_detach_client,
|
|
.command =qisda_iic_command
|
|
};
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
//Tony 090615 start
|
|
#define NEW_TCOM_BOARD
|
|
//Tony 090615 end
|
|
|
|
unsigned char qisda_iic_read(struct i2c_client *client, unsigned char subaddr)
|
|
{
|
|
int ret;
|
|
unsigned char buf[1];
|
|
struct i2c_msg msg = { client->addr, 0, 1, buf };
|
|
buf[0] = subaddr;
|
|
|
|
//Tony test
|
|
#ifdef QISDA_TEST_GPIO_PROBE
|
|
writel(readl(g_pGPIOReg_GPFCON+0x04) & (0x0<<0), g_pGPIOReg_GPFCON+0x04);
|
|
#endif
|
|
|
|
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
|
|
if (ret == -EIO) {
|
|
printk(" I2C read Error, subaddr: 0x%x \n", subaddr);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//Tony test
|
|
#ifdef QISDA_TEST_GPIO_PROBE
|
|
writel(readl(g_pGPIOReg_GPFCON+0x04) | (0x1<<0), g_pGPIOReg_GPFCON+0x04);
|
|
#endif
|
|
|
|
msg.flags = I2C_M_RD ;
|
|
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
|
|
|
|
//Tony test
|
|
#ifdef QISDA_TEST_GPIO_PROBE
|
|
writel(readl(g_pGPIOReg_GPFCON+0x04) & (0x0<<0), g_pGPIOReg_GPFCON+0x04);
|
|
#endif
|
|
|
|
return buf[0];
|
|
}
|
|
|
|
static int qisda_iic_write(struct i2c_client *client, unsigned char subaddr, unsigned char val)
|
|
{
|
|
unsigned char buf[2];
|
|
int ret;
|
|
struct i2c_msg msg = { client->addr, 0, 2, buf };
|
|
buf[0] = subaddr;
|
|
buf[1] = val;
|
|
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
|
|
|
|
if(ret == -EIO){
|
|
printk(" I2C write Error, subaddr: 0x%x \n", subaddr);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int qisda_iic_attach_adapter(struct i2c_adapter *adapter)
|
|
{
|
|
return i2c_probe(adapter, &addr_data, qisda_iic_detect);
|
|
}
|
|
|
|
/* This function is called by i2c_probe */
|
|
static int qisda_iic_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
{
|
|
struct i2c_client *new_client;
|
|
struct qisda_iic_data *data;
|
|
int err = 0;
|
|
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) goto exit;
|
|
if (!(data = kzalloc(sizeof(struct qisda_iic_data), GFP_KERNEL))) {
|
|
err = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
new_client = &data->client;
|
|
i2c_set_clientdata(new_client, data);
|
|
new_client->addr = address;
|
|
new_client->adapter = adapter;
|
|
new_client->driver = &qisda_iic_driver;
|
|
new_client->flags = 0;
|
|
|
|
/* Fill in the remaining client fields */
|
|
strlcpy(new_client->name, "qisda_iic", I2C_NAME_SIZE);
|
|
data->valid = 0;
|
|
mutex_init(&data->update_lock);
|
|
|
|
/* Tell the I2C layer a new client has arrived */
|
|
if ((err = i2c_attach_client(new_client))) goto exit_kfree;
|
|
//Tell the s3c_ts_iic. It is ready to initialize the panel by setting interrupt mode.
|
|
//Then it will callback to the command
|
|
if ((err = s3c_ts_iic_port_init(new_client))) goto exit_kfree;;
|
|
|
|
return err;
|
|
|
|
exit_kfree:
|
|
i2c_detach_client(new_client);
|
|
kfree(data);
|
|
exit:
|
|
printk(KERN_INFO "qisda_iic_detect return error\n");
|
|
return err;
|
|
}
|
|
|
|
static int qisda_iic_detach_client(struct i2c_client *client)
|
|
{
|
|
int err;
|
|
err = i2c_detach_client(client);
|
|
if (err)
|
|
return err;
|
|
kfree(i2c_get_clientdata(client));
|
|
return 0;
|
|
}
|
|
static int qisda_iic_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
{
|
|
unsigned char u8return,u8x1,u8x0,u8y1,u8y0;
|
|
unsigned int *pos;
|
|
#define INT_MODE_ENABLE (1<<3)
|
|
#define INT_MODE_HIGH_ACTIVE (1<<2)
|
|
#define INT_MODE_TOUCH_INDICATE (1<<1)
|
|
#define INT_MODE_DIFFERENCE (1<<0)
|
|
switch(cmd)
|
|
{
|
|
case QISDA_IIC_INIT:
|
|
//Set interrupt mode. Enable interrupt, Low active.
|
|
//Tony test
|
|
#ifdef QISDA_TEST_GPIO_PROBE
|
|
g_pGPIOReg_GPFCON = ioremap(0x56000050, 0x00100000);
|
|
writel(readl(g_pGPIOReg_GPFCON) | (0x1<<0), g_pGPIOReg_GPFCON);
|
|
writel(readl(g_pGPIOReg_GPFCON+0x04) | (0x1<<0), g_pGPIOReg_GPFCON+0x04);
|
|
writel(readl(g_pGPIOReg_GPFCON+0x08) | (0x2<<0), g_pGPIOReg_GPFCON+0x08);
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef NEW_TCOM_BOARD
|
|
//printk(KERN_INFO "qisda_iic_detect INIT 1111\n");
|
|
//mdelay(300);
|
|
//if(qisda_iic_write(client, 0x78, 0x3) < 0) return -EIO;
|
|
//mdelay(250);
|
|
//printk(KERN_INFO "qisda_iic_command INIT 2222\n");
|
|
if(qisda_iic_write(client, 0x71, 0xA) < 0) return -EIO;
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8return= qisda_iic_read(client, 0x71);
|
|
printk(KERN_INFO "qisda_iic_command INIT =0x%x\n",u8return);
|
|
qisda_iic_write(client, 0x6F, 0x22);
|
|
qisda_iic_write(client, 0x70, 0x22);
|
|
|
|
#else // old
|
|
printk(KERN_INFO "qisda_iic_command INIT 1111\n");
|
|
mdelay(6000);
|
|
qisda_iic_write(client, 0x78, 0x3);
|
|
printk(KERN_INFO "qisda_iic_command INIT 2222\n");
|
|
qisda_iic_write(client, 0x71,INT_MODE_ENABLE | INT_MODE_TOUCH_INDICATE);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8return= qisda_iic_read(client, 0x71);
|
|
printk(KERN_INFO "qisda_iic_command INIT =0x%x\n",u8return);
|
|
#endif
|
|
|
|
break;
|
|
case QISDA_IIC_READ_POSITION:
|
|
pos = arg;
|
|
#ifdef NEW_TCOM_BOARD
|
|
u8x0= qisda_iic_read(client, 0x00);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8x1= qisda_iic_read(client, 0x01);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8y0= qisda_iic_read(client, 0x02);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8y1= qisda_iic_read(client, 0x03);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
#else
|
|
u8x0= qisda_iic_read(client, 0x54);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8x1= qisda_iic_read(client, 0x58);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8y0= qisda_iic_read(client, 0x55);
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8y1= qisda_iic_read(client, 0x59);
|
|
#endif
|
|
udelay(DELAY_TIME_IIC_READ);
|
|
u8x1 &= 0x3;
|
|
u8y1 &= 0x3;
|
|
#ifdef ROTATE_NAGATIVE_90
|
|
pos[0] = (unsigned int)u8x1*256 + u8x0;
|
|
pos[1] = (unsigned int)u8y1*256+ u8y0;
|
|
|
|
if(!((pos[0] ==0) && (pos[1]==0)))
|
|
{
|
|
pos[1] = (unsigned int)u8x1*256 + u8x0 -1;
|
|
pos[0] = (unsigned int)u8y1*256+ u8y0;
|
|
|
|
/*kit.mod 20090811*/
|
|
#if defined(AUO_EPAPER_6_INCH)
|
|
pos[0] = 601 - pos[0] -1;
|
|
#elif defined(AUO_EPAPER_9_INCH)
|
|
pos[0] = 769 - pos[0] -1;
|
|
#endif
|
|
/*kit.end*/
|
|
}
|
|
|
|
|
|
#else
|
|
pos[0] = (unsigned int)u8x1*256 + u8x0;
|
|
pos[1] = (unsigned int)u8y1*256+ u8y0;
|
|
#endif
|
|
//printk("X: %d, Y: %d\n", pos[0], pos[1]);
|
|
break;
|
|
|
|
case QISDA_IIC_CALIBRATION:
|
|
if(qisda_iic_write(client, 0x78, 0x3) < 0){
|
|
printk("CALIBRATION ERROR!");
|
|
return -EIO;
|
|
}
|
|
msleep(300);
|
|
break;
|
|
|
|
case QISDA_IIC_ACTIVE_MODE:
|
|
printk("ACTIVE MODE\n");
|
|
qisda_iic_write(client, 0x73, 0x50);
|
|
msleep(5);
|
|
break;
|
|
|
|
case QISDA_IIC_SLEEP_MODE:
|
|
printk("SLEEP MODE\n");
|
|
qisda_iic_write(client, 0x73, 0x51);
|
|
msleep(5);
|
|
break;
|
|
|
|
case QISDA_IIC_DEEPSLEEP_MODE:
|
|
printk("DEEP SLEEP MODE\n");
|
|
qisda_iic_write(client, 0x73, 0x52);
|
|
msleep(5);
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __init qisda_iic_init(void) { return i2c_add_driver(&qisda_iic_driver); }
|
|
static void __exit qisda_iic_exit(void) { i2c_del_driver(&qisda_iic_driver); }
|
|
MODULE_AUTHOR("Tony YC Huang@qisda.com");
|
|
MODULE_DESCRIPTION("IIC interface for Qisda");
|
|
MODULE_LICENSE("GPL");
|
|
module_init(qisda_iic_init);
|
|
module_exit(qisda_iic_exit);
|