/* eeprom.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (C) 1998, 1999 Frodo Looijaard and Philip Edelbrock Copyright (C) 2003 Greg Kroah-Hartman Copyright (C) 2003 IBM Corp. 2004-01-16 Jean Delvare 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 #include #include #include #include #include #include #include #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 /*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);