From aaee33b95253d0703a35e21bfca8ee2482c47a8e Mon Sep 17 00:00:00 2001 From: linjh Date: Wed, 10 Oct 2012 19:14:05 +0800 Subject: [PATCH] rk2928-phonepad-sdk: add ap321xx l/p sensor and byd693x tp support [reference files] modified: arch/arm/configs/rk2928_phonepad_defconfig arch/arm/mach-rk2928/board-rk2928-phonepad.c arch/arm/mach-rk2928/include/mach/board.h drivers/input/misc/Kconfig drivers/input/misc/Makefile drivers/input/touchscreen/Kconfig drivers/input/touchscreen/Makefile new file: drivers/input/misc/ap321xx.c drivers/input/touchscreen/byd693x_ts.c drivers/input/touchscreen/byd693x_ts.h --- arch/arm/configs/rk2928_phonepad_defconfig | 2 + arch/arm/mach-rk2928/board-rk2928-phonepad.c | 21 + arch/arm/mach-rk2928/include/mach/board.h | 24 + drivers/input/misc/Kconfig | 6 + drivers/input/misc/Makefile | 2 +- drivers/input/misc/ap321xx.c | 1395 ++++++++++++++++++ drivers/input/touchscreen/Kconfig | 4 + drivers/input/touchscreen/Makefile | 2 + drivers/input/touchscreen/byd693x_ts.c | 720 +++++++++ drivers/input/touchscreen/byd693x_ts.h | 43 + 10 files changed, 2218 insertions(+), 1 deletion(-) create mode 100644 drivers/input/misc/ap321xx.c create mode 100644 drivers/input/touchscreen/byd693x_ts.c create mode 100644 drivers/input/touchscreen/byd693x_ts.h diff --git a/arch/arm/configs/rk2928_phonepad_defconfig b/arch/arm/configs/rk2928_phonepad_defconfig index 64551a783d2a..72ad4b792c38 100644 --- a/arch/arm/configs/rk2928_phonepad_defconfig +++ b/arch/arm/configs/rk2928_phonepad_defconfig @@ -239,7 +239,9 @@ CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_I30=y +CONFIG_TOUCHSCREEN_BYD693X=y CONFIG_INPUT_MISC=y +CONFIG_INPUT_AP321XX=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_SENSOR_DEVICE=y diff --git a/arch/arm/mach-rk2928/board-rk2928-phonepad.c b/arch/arm/mach-rk2928/board-rk2928-phonepad.c index 26762b3dd212..a0ee44695c6d 100755 --- a/arch/arm/mach-rk2928/board-rk2928-phonepad.c +++ b/arch/arm/mach-rk2928/board-rk2928-phonepad.c @@ -378,6 +378,18 @@ struct ft5306_platform_data ft5306_info = { }; #endif +#if defined(CONFIG_TOUCHSCREEN_BYD693X) + +#define TOUCH_RESET_PIN RK2928_PIN3_PD5 +#define TOUCH_INT_PIN RK2928_PIN3_PC7 +struct byd_platform_data byd693x_info = { + .int_pin = TOUCH_INT_PIN, + .rst_pin = TOUCH_RESET_PIN, + .screen_max_x = 800, + .screen_max_y = 480, + .xpol = -1, +}; +#endif /*MMA7660 gsensor*/ #if defined (CONFIG_GS_MMA7660) @@ -883,6 +895,15 @@ static struct i2c_board_info __initdata i2c2_info[] = { .platform_data = &ft5306_info, }, #endif +#if defined(CONFIG_TOUCHSCREEN_BYD693X) + { + .type = "byd693x-ts", + .addr = 0x52, + .flags = 0, + .irq = TOUCH_INT_PIN, + .platform_data = &byd693x_info, + }, +#endif }; #endif #ifdef CONFIG_I2C3_RK30 diff --git a/arch/arm/mach-rk2928/include/mach/board.h b/arch/arm/mach-rk2928/include/mach/board.h index 2040eb35fa47..2f012fd005d5 100644 --- a/arch/arm/mach-rk2928/include/mach/board.h +++ b/arch/arm/mach-rk2928/include/mach/board.h @@ -99,6 +99,23 @@ struct ft5306_platform_data { void (*exit_platform_hw)(void); }; #endif +#if defined(CONFIG_TOUCHSCREEN_BYD693X) +struct byd_platform_data { + u16 model; + int pwr_pin; + int int_pin; + int rst_pin; + int pwr_on_value; + int *tp_flag; + + uint16_t screen_max_x; + uint16_t screen_max_y; + u8 swap_xy :1; + u8 xpol :1; + u8 ypol :1; +}; +#endif + #if defined (CONFIG_GPIOEXP_AW9523B) struct gpio_exp_platform_data { @@ -107,6 +124,13 @@ struct gpio_exp_platform_data { }; #endif +#ifdef CONFIG_INPUT_AP321XX +struct ap321xx_platform_data { + int (*init_platform_hw)(void); + void (*exit_platform_hw)(void); +}; +#endif + enum _periph_pll { periph_pll_1485mhz = 148500000, periph_pll_297mhz = 297000000, diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index b2d165feab47..f5ab923449ec 100755 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -21,6 +21,12 @@ config INPUT_LPSENSOR_CM3602 config INPUT_LPSENSOR_AL3006 tristate "al3006 l/p sensor input support" +config INPUT_AP321XX + tristate "ap321xx light and proximity sensor support" + default n + help + To have support for AP321XX serial light and proximity sensor. + config INPUT_88PM860X_ONKEY tristate "88PM860x ONKEY support" depends on MFD_88PM860X diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 93e4103aa35f..1619523e8e58 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -52,4 +52,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_LPSENSOR_AL3006) += al3006.o - +obj-$(CONFIG_INPUT_AP321XX) += ap321xx.o diff --git a/drivers/input/misc/ap321xx.c b/drivers/input/misc/ap321xx.c new file mode 100644 index 000000000000..495123bc8ad0 --- /dev/null +++ b/drivers/input/misc/ap321xx.c @@ -0,0 +1,1395 @@ +/* + * This file is part of the AP3212B, AP3212C and AP3216C sensor driver. + * AP3212B is combined proximity and ambient light sensor. + * AP3216C is combined proximity, ambient light sensor and IRLED. + * + * Contact: YC Hou + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * + * Filename: ap321XX.c + * + * Summary: + * AP3212B v1.5-1.8 and AP3212C/AP3216C v2.0-v2.3 sensor dirver. + * + * Modification History: + * Date By Summary + * -------- -------- ------------------------------------------------------- + * 06/28/11 YC Original Creation (Test version:1.0) + * 06/28/11 YC Change dev name to dyna for demo purpose (ver 1.5). + * 08/29/11 YC Add engineer mode. Change version to 1.6. + * 09/26/11 YC Add calibration compensation function and add not power up + * prompt. Change version to 1.7. + * 02/02/12 YC 1. Modify irq function to seperate two interrupt routine. + * 2. Fix the index of reg array error in em write. + * 02/22/12 YC 3. Merge AP3212B and AP3216C into the same driver. (ver 1.8) + * 03/01/12 YC Add AP3212C into the driver. (ver 1.8) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#define AP3212B_DRV_NAME "ap321xx" +#define DRIVER_VERSION "1.8" + +#define AP3212B_NUM_CACHABLE_REGS 23 +#define AP3216C_NUM_CACHABLE_REGS 26 + +#define AP3212B_RAN_COMMAND 0x10 +#define AP3212B_RAN_MASK 0x30 +#define AP3212B_RAN_SHIFT (4) + +#define AP3212B_MODE_COMMAND 0x00 +#define AP3212B_MODE_SHIFT (0) +#define AP3212B_MODE_MASK 0x07 + +#define AL3212_ADC_LSB 0x0c +#define AL3212_ADC_MSB 0x0d + +#define AL3212_PX_LSB 0x0e +#define AL3212_PX_MSB 0x0f +#define AL3212_PX_LSB_MASK 0x0f +#define AL3212_PX_MSB_MASK 0x3f + +#define AP3212B_OBJ_COMMAND 0x0f +#define AP3212B_OBJ_MASK 0x80 +#define AP3212B_OBJ_SHIFT (7) + +#define AP3212B_INT_COMMAND 0x01 +#define AP3212B_INT_SHIFT (0) +#define AP3212B_INT_MASK 0x03 +#define AP3212B_INT_PMASK 0x02 +#define AP3212B_INT_AMASK 0x01 + +#define AP3212B_ALS_LTHL 0x1a +#define AP3212B_ALS_LTHL_SHIFT (0) +#define AP3212B_ALS_LTHL_MASK 0xff + +#define AP3212B_ALS_LTHH 0x1b +#define AP3212B_ALS_LTHH_SHIFT (0) +#define AP3212B_ALS_LTHH_MASK 0xff + +#define AP3212B_ALS_HTHL 0x1c +#define AP3212B_ALS_HTHL_SHIFT (0) +#define AP3212B_ALS_HTHL_MASK 0xff + +#define AP3212B_ALS_HTHH 0x1d +#define AP3212B_ALS_HTHH_SHIFT (0) +#define AP3212B_ALS_HTHH_MASK 0xff + +#define AP3212B_PX_LTHL 0x2a +#define AP3212B_PX_LTHL_SHIFT (0) +#define AP3212B_PX_LTHL_MASK 0x03 + +#define AP3212B_PX_LTHH 0x2b +#define AP3212B_PX_LTHH_SHIFT (0) +#define AP3212B_PX_LTHH_MASK 0xff + +#define AP3212B_PX_HTHL 0x2c +#define AP3212B_PX_HTHL_SHIFT (0) +#define AP3212B_PX_HTHL_MASK 0x03 + +#define AP3212B_PX_HTHH 0x2d +#define AP3212B_PX_HTHH_SHIFT (0) +#define AP3212B_PX_HTHH_MASK 0xff + +#define AP3212B_PX_CONFIGURE 0x20 + +#define PSENSOR_IOCTL_MAGIC 'c' +#define PSENSOR_IOCTL_GET_ENABLED _IOR(PSENSOR_IOCTL_MAGIC, 1, int *) +#define PSENSOR_IOCTL_ENABLE _IOW(PSENSOR_IOCTL_MAGIC, 2, int *) + +#define LIGHTSENSOR_IOCTL_MAGIC 'l' +#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *) +#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) + + +#define LSC_DBG +#ifdef LSC_DBG +#define LDBG(s,args...) {printk("LDBG: func [%s], line [%d], ",__func__,__LINE__); printk(s,## args);} +#else +#define LDBG(s,args...) {} +#endif + +struct ap321xx_data { + struct i2c_client *client; + u8 reg_cache[AP3216C_NUM_CACHABLE_REGS]; + u8 power_state_before_suspend; + int irq; + struct input_dev *psensor_input_dev; + struct input_dev *lsensor_input_dev; +}; + +// AP3216C / AP3212C register +static u8 ap3216c_reg[AP3216C_NUM_CACHABLE_REGS] = + {0x00,0x01,0x02,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x19,0x1a,0x1b,0x1c,0x1d, + 0x20,0x21,0x22,0x23,0x24,0x28,0x29,0x2a,0x2b,0x2c,0x2d}; + +// AP3216C / AP3212C range +static int ap3216c_range[4] = {23360,5840,1460,265}; + +// AP3212B register +static u8 ap3212b_reg[AP3212B_NUM_CACHABLE_REGS] = + {0x00,0x01,0x02,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x1a,0x1b,0x1c,0x1d, + 0x20,0x21,0x22,0x23,0x2a,0x2b,0x2c,0x2d}; + +// AP3212B range +static int ap3212b_range[4] = {65535,16383,4095,1023}; + +static u16 ap321xx_threshole[8] = {28,444,625,888,1778,3555,7222,0xffff}; + +static u8 *reg_array; +static int *range; +static int reg_num = 0; + +static int cali = 100; + +#define ADD_TO_IDX(addr,idx) { \ + int i; \ + for(i = 0; i < reg_num; i++) \ + { \ + if (addr == reg_array[i]) \ + { \ + idx = i; \ + break; \ + } \ + } \ + } + + +/* + * register access helpers + */ + +static int __ap321xx_read_reg(struct i2c_client *client, + u32 reg, u8 mask, u8 shift) +{ + struct ap321xx_data *data = i2c_get_clientdata(client); + u8 idx = 0xff; + + ADD_TO_IDX(reg,idx) + return (data->reg_cache[idx] & mask) >> shift; +} + +static int __ap321xx_write_reg(struct i2c_client *client, + u32 reg, u8 mask, u8 shift, u8 val) +{ + struct ap321xx_data *data = i2c_get_clientdata(client); + int ret = 0; + u8 tmp; + u8 idx = 0xff; + + ADD_TO_IDX(reg,idx) + if (idx >= reg_num) + return -EINVAL; + + tmp = data->reg_cache[idx]; + tmp &= ~mask; + tmp |= val << shift; + + ret = i2c_smbus_write_byte_data(client, reg, tmp); + if (!ret) + data->reg_cache[idx] = tmp; + + return ret; +} + +/* + * internally used functions + */ + +/* range */ +static int ap321xx_get_range(struct i2c_client *client) +{ + u8 idx = __ap321xx_read_reg(client, AP3212B_RAN_COMMAND, + AP3212B_RAN_MASK, AP3212B_RAN_SHIFT); + return range[idx]; +} + +static int ap321xx_set_range(struct i2c_client *client, int range) +{ + return __ap321xx_write_reg(client, AP3212B_RAN_COMMAND, + AP3212B_RAN_MASK, AP3212B_RAN_SHIFT, range);; +} + + +/* mode */ +static int ap321xx_get_mode(struct i2c_client *client) +{ + int ret; + + ret = __ap321xx_read_reg(client, AP3212B_MODE_COMMAND, + AP3212B_MODE_MASK, AP3212B_MODE_SHIFT); + return ret; +} + +static int ap321xx_set_mode(struct i2c_client *client, int mode) +{ + int ret; + + ret = __ap321xx_write_reg(client, AP3212B_MODE_COMMAND, + AP3212B_MODE_MASK, AP3212B_MODE_SHIFT, mode); + return ret; +} + +/* ALS low threshold */ +static int ap321xx_get_althres(struct i2c_client *client) +{ + int lsb, msb; + lsb = __ap321xx_read_reg(client, AP3212B_ALS_LTHL, + AP3212B_ALS_LTHL_MASK, AP3212B_ALS_LTHL_SHIFT); + msb = __ap321xx_read_reg(client, AP3212B_ALS_LTHH, + AP3212B_ALS_LTHH_MASK, AP3212B_ALS_LTHH_SHIFT); + return ((msb << 8) | lsb); +} + +static int ap321xx_set_althres(struct i2c_client *client, int val) +{ + int lsb, msb, err; + + msb = val >> 8; + lsb = val & AP3212B_ALS_LTHL_MASK; + + err = __ap321xx_write_reg(client, AP3212B_ALS_LTHL, + AP3212B_ALS_LTHL_MASK, AP3212B_ALS_LTHL_SHIFT, lsb); + if (err) + return err; + + err = __ap321xx_write_reg(client, AP3212B_ALS_LTHH, + AP3212B_ALS_LTHH_MASK, AP3212B_ALS_LTHH_SHIFT, msb); + + return err; +} + +/* ALS high threshold */ +static int ap321xx_get_ahthres(struct i2c_client *client) +{ + int lsb, msb; + lsb = __ap321xx_read_reg(client, AP3212B_ALS_HTHL, + AP3212B_ALS_HTHL_MASK, AP3212B_ALS_HTHL_SHIFT); + msb = __ap321xx_read_reg(client, AP3212B_ALS_HTHH, + AP3212B_ALS_HTHH_MASK, AP3212B_ALS_HTHH_SHIFT); + return ((msb << 8) | lsb); +} + +static int ap321xx_set_ahthres(struct i2c_client *client, int val) +{ + int lsb, msb, err; + + msb = val >> 8; + lsb = val & AP3212B_ALS_HTHL_MASK; + + err = __ap321xx_write_reg(client, AP3212B_ALS_HTHL, + AP3212B_ALS_HTHL_MASK, AP3212B_ALS_HTHL_SHIFT, lsb); + if (err) + return err; + + err = __ap321xx_write_reg(client, AP3212B_ALS_HTHH, + AP3212B_ALS_HTHH_MASK, AP3212B_ALS_HTHH_SHIFT, msb); + + return err; +} + +/* PX low threshold */ +static int ap321xx_get_plthres(struct i2c_client *client) +{ + int lsb, msb; + lsb = __ap321xx_read_reg(client, AP3212B_PX_LTHL, + AP3212B_PX_LTHL_MASK, AP3212B_PX_LTHL_SHIFT); + msb = __ap321xx_read_reg(client, AP3212B_PX_LTHH, + AP3212B_PX_LTHH_MASK, AP3212B_PX_LTHH_SHIFT); + return ((msb << 2) | lsb); +} + +static int ap321xx_set_plthres(struct i2c_client *client, int val) +{ + int lsb, msb, err; + + msb = val >> 2; + lsb = val & AP3212B_PX_LTHL_MASK; + + err = __ap321xx_write_reg(client, AP3212B_PX_LTHL, + AP3212B_PX_LTHL_MASK, AP3212B_PX_LTHL_SHIFT, lsb); + if (err) + return err; + + err = __ap321xx_write_reg(client, AP3212B_PX_LTHH, + AP3212B_PX_LTHH_MASK, AP3212B_PX_LTHH_SHIFT, msb); + + return err; +} + +/* PX high threshold */ +static int ap321xx_get_phthres(struct i2c_client *client) +{ + int lsb, msb; + lsb = __ap321xx_read_reg(client, AP3212B_PX_HTHL, + AP3212B_PX_HTHL_MASK, AP3212B_PX_HTHL_SHIFT); + msb = __ap321xx_read_reg(client, AP3212B_PX_HTHH, + AP3212B_PX_HTHH_MASK, AP3212B_PX_HTHH_SHIFT); + return ((msb << 2) | lsb); +} + +static int ap321xx_set_phthres(struct i2c_client *client, int val) +{ + int lsb, msb, err; + + msb = val >> 2; + lsb = val & AP3212B_ALS_HTHL_MASK; + + err = __ap321xx_write_reg(client, AP3212B_PX_HTHL, + AP3212B_PX_HTHL_MASK, AP3212B_PX_HTHL_SHIFT, lsb); + if (err) + return err; + + err = __ap321xx_write_reg(client, AP3212B_PX_HTHH, + AP3212B_PX_HTHH_MASK, AP3212B_PX_HTHH_SHIFT, msb); + + return err; +} + +static int ap321xx_get_adc_value(struct i2c_client *client) +{ + unsigned int lsb, msb, val; +#ifdef LSC_DBG + unsigned int tmp,range; +#endif + unsigned char index=0; + + lsb = i2c_smbus_read_byte_data(client, AL3212_ADC_LSB); + + if (lsb < 0) { + return lsb; + } + + msb = i2c_smbus_read_byte_data(client, AL3212_ADC_MSB); + + if (msb < 0) + return msb; + +#ifdef LSC_DBG + range = ap321xx_get_range(client); + tmp = (((msb << 8) | lsb) * range) >> 16; + tmp = tmp * cali / 100; + LDBG("ALS val=%d lux\n",tmp); +#endif + val = msb << 8 | lsb; + for(index = 0; index < 7 && val > ap321xx_threshole[index];index++) + ; + + return index; +} + +static int ap321xx_get_object(struct i2c_client *client) +{ + int val; + + val = i2c_smbus_read_byte_data(client, AP3212B_OBJ_COMMAND); + val &= AP3212B_OBJ_MASK; + + return val >> AP3212B_OBJ_SHIFT; +} + +static int ap321xx_get_intstat(struct i2c_client *client) +{ + int val; + + val = i2c_smbus_read_byte_data(client, AP3212B_INT_COMMAND); + val &= AP3212B_INT_MASK; + + return val >> AP3212B_INT_SHIFT; +} + + +static int ap321xx_get_px_value(struct i2c_client *client) +{ + int lsb, msb; + + lsb = i2c_smbus_read_byte_data(client, AL3212_PX_LSB); + + if (lsb < 0) { + return lsb; + } + + msb = i2c_smbus_read_byte_data(client, AL3212_PX_MSB); + + if (msb < 0) + return msb; + + return (u32)(((msb & AL3212_PX_MSB_MASK) << 4) | (lsb & AL3212_PX_LSB_MASK)); +} + +#if 0 +/* + * sysfs layer + */ +static int ap321xx_input_init(struct ap321xx_data *data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) { + return -ENOMEM; + } + dev->name = "lightsensor-level"; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_capability(dev, EV_ABS, ABS_RUDDER); + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->input = dev; + + return 0; +} + +static void ap321xx_input_fini(struct ap321xx_data *data) +{ + struct input_dev *dev = data->input; + + input_unregister_device(dev); + input_free_device(dev); +} +#else +static int ap321xx_lsensor_open(struct inode *inode, struct file *file); +static int ap321xx_lsensor_release(struct inode *inode, struct file *file); +static long ap321xx_lsensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static void ap321xx_change_ls_threshold(struct i2c_client *client); + +static int misc_ls_opened = 0; +static struct file_operations ap321xx_lsensor_fops = { + .owner = THIS_MODULE, + .open = ap321xx_lsensor_open, + .release = ap321xx_lsensor_release, + .unlocked_ioctl = ap321xx_lsensor_ioctl +}; + +static struct miscdevice ap321xx_lsensor_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lightsensor", + .fops = &ap321xx_lsensor_fops +}; + +static int ap321xx_lsensor_open(struct inode *inode, struct file *file) +{ + LDBG("\n"); + if (misc_ls_opened) + return -EBUSY; + misc_ls_opened = 1; + return 0; +} + +static int ap321xx_lsensor_release(struct inode *inode, struct file *file) +{ + LDBG("\n"); + misc_ls_opened = 0; + return 0; +} + +static int ap321xx_lsensor_enable(struct i2c_client *client) +{ + int ret = 0,mode; + + mode = ap321xx_get_mode(client); + if((mode & 0x01) == 0){ + mode |= 0x01; + ret = ap321xx_set_mode(client,mode); + } + + return ret; +} + +static int ap321xx_lsensor_disable(struct i2c_client *client) +{ + int ret = 0,mode; + + mode = ap321xx_get_mode(client); + if(mode & 0x01){ + mode &= ~0x01; + if(mode == 0x04) + mode = 0; + ret = ap321xx_set_mode(client,mode); + } + + return ret; +} + +static long ap321xx_lsensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + char val; + int ret; + struct i2c_client *client = container_of(ap321xx_lsensor_misc.parent, struct i2c_client, dev); + + LDBG("%s cmd %d\n", __FUNCTION__, _IOC_NR(cmd)); + + switch (cmd) { + case LIGHTSENSOR_IOCTL_ENABLE: + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + if (val){ + ret = ap321xx_lsensor_enable(client); + if(!ret){ + msleep(200); + ap321xx_change_ls_threshold(client); + } + return ret; + } + else + return ap321xx_lsensor_disable(client); + break; + case LIGHTSENSOR_IOCTL_GET_ENABLED: + val = ap321xx_get_mode(client); + val &= 0x01; + return put_user(val, (unsigned long __user *)arg); + break; + default: + pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd)); + return -EINVAL; + } +} + +static int ap321xx_register_lsensor_device(struct i2c_client *client, struct ap321xx_data *data) +{ + struct input_dev *input_dev; + int rc; + + LDBG("allocating input device lsensor\n"); + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev,"%s: could not allocate input device for lsensor\n", __FUNCTION__); + rc = -ENOMEM; + goto done; + } + data->lsensor_input_dev = input_dev; + input_set_drvdata(input_dev, data); + input_dev->name = "lightsensor-level"; + input_dev->dev.parent = &client->dev; + set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_MISC, 0, 8, 0, 0); + + rc = input_register_device(input_dev); + if (rc < 0) { + pr_err("%s: could not register input device for lsensor\n", __FUNCTION__); + goto done; + } + rc = misc_register(&ap321xx_lsensor_misc); + if (rc < 0) { + pr_err("%s: could not register misc device lsensor\n", __FUNCTION__); + goto err_unregister_input_device; + } + + ap321xx_lsensor_misc.parent = &client->dev; + return 0; + +err_unregister_input_device: + input_unregister_device(input_dev); +done: + return rc; +} + +static void ap321xx_unregister_lsensor_device(struct i2c_client *client, struct ap321xx_data *data) +{ + misc_deregister(&ap321xx_lsensor_misc); + input_unregister_device(data->lsensor_input_dev); +} + +static void ap321xx_change_ls_threshold(struct i2c_client *client) +{ + struct ap321xx_data *data = i2c_get_clientdata(client); + int value; + + value = ap321xx_get_adc_value(client); + LDBG("ALS lux index: %u\n", value); + if(value > 0){ + ap321xx_set_althres(client,ap321xx_threshole[value-1]); + ap321xx_set_ahthres(client,ap321xx_threshole[value]); + } + else{ + ap321xx_set_althres(client,0); + ap321xx_set_ahthres(client,ap321xx_threshole[value]); + } + + input_report_abs(data->lsensor_input_dev, ABS_MISC, value); + input_sync(data->lsensor_input_dev); + +} + + +static int misc_ps_opened = 0; +static int ap321xx_psensor_open(struct inode *inode, struct file *file); +static int ap321xx_psensor_release(struct inode *inode, struct file *file); +static long ap321xx_psensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + +static struct file_operations ap321xx_psensor_fops = { + .owner = THIS_MODULE, + .open = ap321xx_psensor_open, + .release = ap321xx_psensor_release, + .unlocked_ioctl = ap321xx_psensor_ioctl +}; + +static struct miscdevice ap321xx_psensor_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "psensor", + .fops = &ap321xx_psensor_fops +}; + +static int ap321xx_psensor_open(struct inode *inode, struct file *file) +{ + LDBG("\n"); + if (misc_ps_opened) + return -EBUSY; + misc_ps_opened = 1; + return 0; +} + +static int ap321xx_psensor_release(struct inode *inode, struct file *file) +{ + LDBG("\n"); + misc_ps_opened = 0; + return 0; +} + +static int ap321xx_psensor_enable(struct i2c_client *client) +{ + int ret = 0,mode; + + mode = ap321xx_get_mode(client); + if((mode & 0x02) == 0){ + mode |= 0x02; + ret = ap321xx_set_mode(client,mode); + } + + return ret; +} + +static int ap321xx_psensor_disable(struct i2c_client *client) +{ + int ret = 0,mode; + + mode = ap321xx_get_mode(client); + if(mode & 0x02){ + mode &= ~0x02; + if(mode == 0x04) + mode = 0x00; + ret = ap321xx_set_mode(client,mode); + } + return ret; +} + + +static long ap321xx_psensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + char val; + struct i2c_client *client = container_of(ap321xx_psensor_misc.parent,struct i2c_client,dev); + + LDBG("%s cmd %d\n", __func__, _IOC_NR(cmd)); + + switch (cmd) { + case PSENSOR_IOCTL_ENABLE: + if (get_user(val, (unsigned long __user *)arg)) + return -EFAULT; + if (val) + return ap321xx_psensor_enable(client); + else + return ap321xx_psensor_disable(client); + break; + case PSENSOR_IOCTL_GET_ENABLED: + val = ap321xx_get_mode(client); + val = (val >> 1) & 0x01; + return put_user(val, (unsigned long __user *)arg); + break; + default: + pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd)); + return -EINVAL; + } +} + +static int ap321xx_register_psensor_device(struct i2c_client *client, struct ap321xx_data *data) +{ + struct input_dev *input_dev; + int rc; + + LDBG("allocating input device psensor\n"); + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev,"%s: could not allocate input device for psensor\n", __FUNCTION__); + rc = -ENOMEM; + goto done; + } + data->psensor_input_dev = input_dev; + input_set_drvdata(input_dev, data); + input_dev->name = "proximity"; + input_dev->dev.parent = &client->dev; + set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0); + + rc = input_register_device(input_dev); + if (rc < 0) { + pr_err("%s: could not register input device for psensor\n", __FUNCTION__); + goto done; + } + + rc = misc_register(&ap321xx_psensor_misc); + if (rc < 0) { + pr_err("%s: could not register misc device psensor\n", __FUNCTION__); + goto err_unregister_input_device; + } + ap321xx_psensor_misc.parent = &client->dev; + return 0; + +err_unregister_input_device: + input_unregister_device(input_dev); +done: + return rc; +} + +static void ap321xx_unregister_psensor_device(struct i2c_client *client, struct ap321xx_data *data) +{ + misc_deregister(&ap321xx_psensor_misc); + input_unregister_device(data->psensor_input_dev); +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend ap321xx_early_suspend; +static void ap321xx_suspend(struct early_suspend *h) +{ + struct i2c_client *client = container_of(ap321xx_lsensor_misc.parent, struct i2c_client, dev); + + if (misc_ps_opened) + ap321xx_psensor_disable(client); + if (misc_ls_opened) + ap321xx_lsensor_disable(client); +} + +static void ap321xx_resume(struct early_suspend *h) +{ + struct i2c_client *client = container_of(ap321xx_lsensor_misc.parent, struct i2c_client, dev); + + if (misc_ls_opened) + ap321xx_lsensor_enable(client); + if (misc_ps_opened) + ap321xx_psensor_enable(client); +} +#endif + +#endif + +/* range */ +static ssize_t ap321xx_show_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%i\n", ap321xx_get_range(data->client)); +} + +static ssize_t ap321xx_store_range(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + unsigned long val; + int ret; + + if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3)) + return -EINVAL; + + ret = ap321xx_set_range(data->client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, + ap321xx_show_range, ap321xx_store_range); + + +/* mode */ +static ssize_t ap321xx_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%d\n", ap321xx_get_mode(data->client)); +} + +static ssize_t ap321xx_store_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + unsigned long val; + int ret; + + if ((strict_strtoul(buf, 10, &val) < 0) || (val > 7)) + return -EINVAL; + + ret = ap321xx_set_mode(data->client, val); + + if (ret < 0) + return ret; + return count; +} + +static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, + ap321xx_show_mode, ap321xx_store_mode); + + +/* lux */ +static ssize_t ap321xx_show_lux(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + + /* No LUX data if power down */ + if (ap321xx_get_mode(data->client) == 0x00) + return sprintf((char*) buf, "%s\n", "Please power up first!"); + + return sprintf(buf, "%d\n", ap321xx_get_adc_value(data->client)); +} + +static DEVICE_ATTR(lux, S_IRUGO, ap321xx_show_lux, NULL); + + +/* Px data */ +static ssize_t ap321xx_show_pxvalue(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + + /* No Px data if power down */ + if (ap321xx_get_mode(data->client) == 0x00) + return -EBUSY; + + return sprintf(buf, "%d\n", ap321xx_get_px_value(data->client)); +} + +static DEVICE_ATTR(pxvalue, S_IRUGO, ap321xx_show_pxvalue, NULL); + + +/* proximity object detect */ +static ssize_t ap321xx_show_object(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%d\n", ap321xx_get_object(data->client)); +} + +static DEVICE_ATTR(object, S_IRUGO, ap321xx_show_object, NULL); + + +/* ALS low threshold */ +static ssize_t ap321xx_show_althres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%d\n", ap321xx_get_althres(data->client)); +} + +static ssize_t ap321xx_store_althres(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + ret = ap321xx_set_althres(data->client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(althres, S_IWUSR | S_IRUGO, + ap321xx_show_althres, ap321xx_store_althres); + + +/* ALS high threshold */ +static ssize_t ap321xx_show_ahthres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%d\n", ap321xx_get_ahthres(data->client)); +} + +static ssize_t ap321xx_store_ahthres(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + ret = ap321xx_set_ahthres(data->client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(ahthres, S_IWUSR | S_IRUGO, + ap321xx_show_ahthres, ap321xx_store_ahthres); + +/* Px low threshold */ +static ssize_t ap321xx_show_plthres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%d\n", ap321xx_get_plthres(data->client)); +} + +static ssize_t ap321xx_store_plthres(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + ret = ap321xx_set_plthres(data->client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(plthres, S_IWUSR | S_IRUGO, + ap321xx_show_plthres, ap321xx_store_plthres); + +/* Px high threshold */ +static ssize_t ap321xx_show_phthres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + return sprintf(buf, "%d\n", ap321xx_get_phthres(data->client)); +} + +static ssize_t ap321xx_store_phthres(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + ret = ap321xx_set_phthres(data->client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(phthres, S_IWUSR | S_IRUGO, + ap321xx_show_phthres, ap321xx_store_phthres); + + +/* calibration */ +static ssize_t ap321xx_show_calibration_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", cali); +} + +static ssize_t ap321xx_store_calibration_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct ap321xx_data *data = input_get_drvdata(input); + int stdls, lux; + char tmp[10]; + + /* No LUX data if not operational */ + if (ap321xx_get_mode(data->client) == 0x00) + { + printk("Please power up first!"); + return -EINVAL; + } + + cali = 100; + sscanf(buf, "%d %s", &stdls, tmp); + + if (!strncmp(tmp, "-setcv", 6)) + { + cali = stdls; + return -EBUSY; + } + + if (stdls < 0) + { + printk("Std light source: [%d] < 0 !!!\nCheck again, please.\n\ + Set calibration factor to 100.\n", stdls); + return -EBUSY; + } + + lux = ap321xx_get_adc_value(data->client); + cali = stdls * 100 / lux; + + return -EBUSY; +} + +static DEVICE_ATTR(calibration, S_IWUSR | S_IRUGO, + ap321xx_show_calibration_state, ap321xx_store_calibration_state); + +#ifdef LSC_DBG +/* engineer mode */ +static ssize_t ap321xx_em_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ap321xx_data *data = i2c_get_clientdata(client); + int i; + u8 tmp; + + for (i = 0; i < reg_num; i++) + { + tmp = i2c_smbus_read_byte_data(data->client, reg_array[i]); + + printk("Reg[0x%x] Val[0x%x]\n", reg_array[i], tmp); + } + + return 0; +} + +static ssize_t ap321xx_em_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ap321xx_data *data = i2c_get_clientdata(client); + u32 addr,val,idx=0; + int ret = 0; + + sscanf(buf, "%x%x", &addr, &val); + + printk("Write [%x] to Reg[%x]...\n",val,addr); + + ret = i2c_smbus_write_byte_data(data->client, addr, val); + ADD_TO_IDX(addr,idx) + if (!ret) + data->reg_cache[idx] = val; + + return count; +} +static DEVICE_ATTR(em, S_IWUSR |S_IRUGO, + ap321xx_em_read, ap321xx_em_write); +#endif + +static struct attribute *ap321xx_attributes[] = { + &dev_attr_range.attr, + &dev_attr_mode.attr, + &dev_attr_lux.attr, + &dev_attr_object.attr, + &dev_attr_pxvalue.attr, + &dev_attr_althres.attr, + &dev_attr_ahthres.attr, + &dev_attr_plthres.attr, + &dev_attr_phthres.attr, + &dev_attr_calibration.attr, +#ifdef LSC_DBG + &dev_attr_em.attr, +#endif + NULL +}; + +static const struct attribute_group ap321xx_attr_group = { + .attrs = ap321xx_attributes, +}; + +static int Product_Detect(struct i2c_client *client) +{ + int mid = i2c_smbus_read_byte_data(client, 0x03); + int pid = i2c_smbus_read_byte_data(client, 0x04); + int rid = i2c_smbus_read_byte_data(client, 0x05); + + if ( mid == 0x01 && pid == 0x01 && + (rid == 0x03 || rid == 0x04) ) + { + LDBG("RevID [%d], ==> DA3212 v1.5~1.8 ...... AP3212B detected\n", rid) + reg_array = ap3212b_reg; + range = ap3212b_range; + reg_num = AP3212B_NUM_CACHABLE_REGS; + } + else if ( (mid == 0x01 && pid == 0x02 && rid == 0x00) || + (mid == 0x02 && pid == 0x02 && rid == 0x01)) + { + LDBG("RevID [%d], ==> DA3212 v2.0 ...... AP3212C/AP3216C detected\n", rid) + reg_array = ap3216c_reg; + range = ap3216c_range; + reg_num = AP3216C_NUM_CACHABLE_REGS; + } + else + { + LDBG("MakeID[%d] ProductID[%d] RevID[%d] .... can't detect ... bad reversion!!!\n", mid, pid, rid) + return -EIO; + } + + + return 0; +} + +static int ap321xx_init_client(struct i2c_client *client) +{ + struct ap321xx_data *data = i2c_get_clientdata(client); + int i; + + /* read all the registers once to fill the cache. + * if one of the reads fails, we consider the init failed */ + for (i = 0; i < reg_num; i++) { + int v = i2c_smbus_read_byte_data(client, reg_array[i]); + if (v < 0) + return -ENODEV; + + data->reg_cache[i] = v; + } + + /* set defaults */ + ap321xx_set_range(client, 0); + ap321xx_set_mode(client, 0); + + return 0; +} + +/* + * I2C layer + */ + +static irqreturn_t ap321xx_irq(int irq, void *data_) +{ + struct ap321xx_data *data = data_; + u8 int_stat; + int Pval; + + int_stat = ap321xx_get_intstat(data->client); + + // ALS int + if (int_stat & AP3212B_INT_AMASK) + { + ap321xx_change_ls_threshold(data->client); + } + + // PX int + if (int_stat & AP3212B_INT_PMASK) + { + Pval = ap321xx_get_object(data->client); + LDBG("%s\n", Pval ? "obj near":"obj far"); + input_report_abs(data->psensor_input_dev, ABS_DISTANCE, Pval); + input_sync(data->psensor_input_dev); + } + + return IRQ_HANDLED; +} + +static int __devinit ap321xx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct ap321xx_platform_data *pdata = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct ap321xx_data *data; + int err = 0; + + LDBG("ap321xx_probe\n"); + + if (pdata->init_platform_hw) { + err = pdata->init_platform_hw(); + if (err < 0) + goto exit_free_gpio; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)){ + err = -EIO; + goto exit_free_gpio; + } + err = Product_Detect(client); + if (err) + { + dev_err(&client->dev, "ret: %d, product version detect failed.\n",err); + err = -EIO; + goto exit_free_gpio; + } + + data = kzalloc(sizeof(struct ap321xx_data), GFP_KERNEL); + if (!data){ + err = -ENOMEM; + goto exit_free_gpio; + } + + data->client = client; + i2c_set_clientdata(client, data); + data->irq = client->irq; + + /* initialize the AP3212B chip */ + err = ap321xx_init_client(client); + if (err) + goto exit_kfree; + + err = ap321xx_register_lsensor_device(client,data); + if (err){ + dev_err(&client->dev, "failed to register_lsensor_device\n"); + goto exit_kfree; + } + + err = ap321xx_register_psensor_device(client, data); + if (err) { + dev_err(&client->dev, "failed to register_psensor_device\n"); + goto exit_free_ls_device; + } + +#if 0 + /* register sysfs hooks */ + err = sysfs_create_group(&data->input->dev.kobj, &ap321xx_attr_group); + if (err) + goto exit_free_ps_device; +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + ap321xx_early_suspend.suspend = ap321xx_suspend; + ap321xx_early_suspend.resume = ap321xx_resume; + ap321xx_early_suspend.level = 0x02; + register_early_suspend(&ap321xx_early_suspend); +#endif + + + err = request_threaded_irq(client->irq, NULL, ap321xx_irq, + IRQF_TRIGGER_FALLING, + "ap321xx", data); + if (err) { + dev_err(&client->dev, "ret: %d, could not get IRQ %d\n",err,client->irq); + goto exit_free_ps_device; + } + + dev_info(&client->dev, "Driver version %s enabled\n", DRIVER_VERSION); + return 0; + +exit_free_ps_device: + ap321xx_unregister_psensor_device(client,data); + +exit_free_ls_device: + ap321xx_unregister_lsensor_device(client,data); + +exit_kfree: + kfree(data); +exit_free_gpio: + if (pdata->exit_platform_hw) { + pdata->exit_platform_hw(); + } + return err; +} + +static int __devexit ap321xx_remove(struct i2c_client *client) +{ + const struct ap321xx_platform_data *pdata = client->dev.platform_data; + struct ap321xx_data *data = i2c_get_clientdata(client); + free_irq(data->irq, data); + +// sysfs_remove_group(&data->input->dev.kobj, &ap321xx_attr_group); + ap321xx_unregister_psensor_device(client,data); + ap321xx_unregister_lsensor_device(client,data); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ap321xx_early_suspend); +#endif + + ap321xx_set_mode(client, 0); + kfree(i2c_get_clientdata(client)); + if (pdata->exit_platform_hw) { + pdata->exit_platform_hw(); + } + return 0; +} + +static const struct i2c_device_id ap321xx_id[] = { + { AP3212B_DRV_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ap321xx_id); + +static struct i2c_driver ap321xx_driver = { + .driver = { + .name = AP3212B_DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ap321xx_probe, + .remove = __devexit_p(ap321xx_remove), + .id_table = ap321xx_id, +}; + +static int __init ap321xx_init(void) +{ + LDBG("ap321xx_init\n"); + return i2c_add_driver(&ap321xx_driver); +} + +static void __exit ap321xx_exit(void) +{ + i2c_del_driver(&ap321xx_driver); +} + +MODULE_AUTHOR("YC Hou, LiteOn-semi corporation."); +MODULE_DESCRIPTION("Test AP3212B, AP3212C and AP3216C driver on mini6410."); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(ap321xx_init); +module_exit(ap321xx_exit); + + diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f845d0cef81d..58ef75385191 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1016,6 +1016,10 @@ config TOUCHSCREEN_I30 tristate "i30 based touchscreens: i30(ft5306) Interface" depends on I2C2_RK29 || I2C2_RK30 +config TOUCHSCREEN_BYD693X + tristate "touchscreen BYD693X I2C Interface" + depends on I2C2_RK29 || I2C2_RK30 + config TOUCHSCREEN_SITRONIX_A720 tristate "SITRONIX based touchscreens: SITRONIX Interface for a720" depends on I2C2_RK29 || I2C2_RK30 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index c16a52bc175e..159f846c813a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -93,3 +93,5 @@ obj-$(CONFIG_LAIBAO_TS) += ft5x0x_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_RK) += rmi4/ obj-$(CONFIG_TOUCHSCREEN_I30) += i30_ts.o +obj-$(CONFIG_TOUCHSCREEN_BYD693X) += byd693x_ts.o + diff --git a/drivers/input/touchscreen/byd693x_ts.c b/drivers/input/touchscreen/byd693x_ts.c new file mode 100644 index 000000000000..02b423040540 --- /dev/null +++ b/drivers/input/touchscreen/byd693x_ts.c @@ -0,0 +1,720 @@ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include //use slot B protocol, Android 4.0 system +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//#include +//#include +//#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND + #include + #include +#endif + + +//#define CONFIG_TS_FUNCTION_CALLED_DEBUG //Display the debug information whitch function is called +//#define CONFIG_TS_PROBE_DEBUG //Display the debug information in byd693x_ts_probe function +//#define CONFIG_TS_I2C_TRANSFER_DEBUG //Display the debug information of IIC transfer +//#define CONFIG_TPKEY_STATUS_DEBUG //Display the debug information of Touch Key status +//#define CONFIG_TS_WORKQUEUE_DEBUG //Display the debug ihnformation of creating work queue +//#define CONFIG_TS_COORDIATE_DEBUG // +//#define CONFIG_TS_CUTEDGE_DEBUG // + +//----------------------------------------// +#define TOUCH_INT_NO SW_INT_IRQNO_PIO //GPIO :set the interrupt +#define byd693x_I2C_NAME "byd693x-ts" + +//----------------------------------------// +struct ChipSetting { + char No; + char Reg; + char Data1; + char Data2; +}; + +#include "byd693x_ts.h" + +#define VERSION "byd693x_20120731_16:52_V1.2_Charles@Raysens@Zed" +#define CTP_NAME "byd693x-ts" + +struct byd_platform_data *byd6932_pdata; + + +#define FINGER_NO_MAX 10 //Define the max finger number, but the really finger number: fetch from .fex file +#define BYD_COORD_READ_ADDR 0x5c + +static int SCREEN_MAX_X = 1024; +static int SCREEN_MAX_Y = 600; +static int Get_Finger_Num = 5; + +#define RESO_X_NO 0 +#define RESO_Y_NO 1 + +struct ChipSetting byd693xcfg_Resolution[]={ +//{ 2,0x08, 200/256, 200%256}, // 1 FTHD_H;FTHD_L //¨º???¡ã¡ä?¨¹?D?¦Ì +//{ 2,0x0A, 120/256, 120%256}, // 2 NTHD_H;NTHD_L //??¨¦¨´?D?¦Ì +{ 2,0x0C, 800/256, 800%256}, // 3 RESX_H;RESX_L //X¡¤?¡À??¨º +{ 2,0x0E, 480/256, 480%256}, // 4 RESY_H;RESY_L //Y¡¤?¡À??¨º +}; + +static void deviceResume(struct i2c_client *client); +static void deviceSuspend(struct i2c_client *client); +void byd693xdeviceInit(struct i2c_client *client); + +//static int byd693x_ts_open(struct input_dev *dev); +//static void byd693x_ts_close(struct input_dev *dev); +static int byd693x_ts_suspend(struct i2c_client *client, pm_message_t mesg); +static int byd693x_ts_resume(struct i2c_client *client); +#ifdef CONFIG_HAS_EARLYSUSPEND +static void byd693x_ts_early_suspend(struct early_suspend *h); +static void byd693x_ts_late_resume(struct early_suspend *h); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static irqreturn_t byd693x_ts_isr(int irq, void *dev_id); +static struct workqueue_struct *byd693x_wq; + + +struct byd_ts_priv { + struct i2c_client *client; + struct input_dev *input; + struct hrtimer timer; + struct work_struct byd_work; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + + int irq; + int FingerNo; + int FingerDetect; + u8 btn_pre_TPKey; + int suspend_opend; +}; + +/*********************************************************** +Read Data from TP through IIC +***********************************************************/ +static int ReadRegister(struct i2c_client *client,uint8_t reg,unsigned char *buf, int ByteLen) +{ +// unsigned char buf[4]; + struct i2c_msg msg[2]; + int ret; + +// memset(buf, 0xFF, sizeof(buf)); + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ® + msg[0].scl_rate=byd693x_I2C_RATE; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = ByteLen; + msg[1].buf = buf; + msg[1].scl_rate=byd693x_I2C_RATE; + + ret = i2c_transfer(client->adapter, msg, 2); + + #ifdef CONFIG_TS_I2C_TRANSFER_DEBUG + if(ret<0) printk(" ReadRegister: i2c_transfer Error !\n"); + else printk(" ReadRegister: i2c_transfer OK !\n"); + #endif + if(ret<0) { return 0; } + else { return 1; } +} + +/*********************************************************** +Write Data to TP through IIC +***********************************************************/ +static void WriteRegister(struct i2c_client *client,uint8_t Reg,unsigned char Data1,unsigned char Data2,int ByteNo) +{ + struct i2c_msg msg; + unsigned char buf[4]; + int ret; + + buf[0]=Reg; + buf[1]=Data1; + buf[2]=Data2; + buf[3]=0; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = ByteNo+1; + msg.buf = (char *)buf; + msg.scl_rate=byd693x_I2C_RATE; + ret = i2c_transfer(client->adapter, &msg, 1); + + #ifdef CONFIG_TS_I2C_TRANSFER_DEBUG + if(ret<0) printk(" WriteRegister: i2c_master_send Error !\n"); + else printk(" WriteRegister: i2c_master_send OK !\n"); + #endif +} + +void byd693xdeviceInit(struct i2c_client *client) +{ + deviceSuspend(client); + deviceResume(client); +mdelay(30); +} + +static void deviceResume(struct i2c_client *client) +{ + int i; + + for(i=0;ibtn_pre_TPKey = TPKey_code[0]; + break; + case 0xa0: + byd_priv->btn_pre_TPKey = TPKey_code[1]; + break; + case 0xb0: + byd_priv->btn_pre_TPKey = TPKey_code[2]; + break; + case 0xc0: + byd_priv->btn_pre_TPKey = TPKey_code[3]; + break; + case 0xf0: + input_report_key(byd_priv->input, byd_priv->btn_pre_TPKey, REPORT_TPKEY_UP); + input_sync(byd_priv->input); + return; + default: + return; + } + input_report_key(byd_priv->input, byd_priv->btn_pre_TPKey, REPORT_TPKEY_DOWN); + input_sync(byd_priv->input); +} + +static void byd693x_ts_work(struct work_struct *work) +{ + int i; + unsigned short xpos=0, ypos=0; + unsigned char Coord_Buf[4*FINGER_NO_MAX +1]; //Define the max finger data + u8 btn_status; + u8 Finger_ID,Finger_Status,Report_Status; + + struct byd_ts_priv *byd_priv = container_of(work,struct byd_ts_priv,byd_work); + + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_work! |\n"); + printk("+-----------------------------------------+\n"); + #endif + if (byd_priv->suspend_opend == 1) + return ; + + ReadRegister(byd_priv->client,BYD_COORD_READ_ADDR,Coord_Buf,(4 * Get_Finger_Num +1)); //read only the used finger number data + + btn_status = Coord_Buf[0]; +#ifdef CONFIG_TS_COORDIATE_DEBUG + printk("btn_status is: 0x%x\n",btn_status); +#endif + + if ( 0x00 == (btn_status & 0x80)) + { + return; + } + + bf693x_ts_send_keyevent(byd_priv,btn_status); + + byd_priv->FingerDetect = 0; + Report_Status = 0; + if ((btn_status & 0x0f)) + { + for(i=0;i< (btn_status & 0x0f);i++) + { + Finger_ID = (Coord_Buf[i*4 + 1]>>4)-1; + Finger_Status = Coord_Buf[i*4 + 3] & 0xf0; + xpos = Coord_Buf[i*4 + 1] & 0x0f; + xpos = (xpos <<8) | Coord_Buf[i*4 + 2]; + + ypos = Coord_Buf[i*4 + 3] & 0x0f; + ypos = (ypos <<8) | Coord_Buf[i*4 + 4]; + + if (byd6932_pdata ->swap_xy) + swap(xpos, ypos); + if (byd6932_pdata ->xpol) + xpos = byd6932_pdata ->screen_max_x -xpos; + if (byd6932_pdata ->ypol) + ypos = byd6932_pdata ->screen_max_y -ypos; + + if((0xa0 == Finger_Status) || (0x90 == Finger_Status)) //0xa0:The first Touch; 0x90: Hold Finger Touch + { + byd_priv->FingerDetect++; + Report_Status = 1; +// printk("Finger_ID = 0x%x, DOWN\n", Finger_ID); + input_mt_slot(byd_priv->input, Finger_ID); //Slot B protocol + input_report_abs(byd_priv->input, ABS_MT_TRACKING_ID, Finger_ID); + input_report_abs(byd_priv->input, ABS_MT_TOUCH_MAJOR, REPORT_TOUCH_MAJOR); //Finger Size + input_report_abs(byd_priv->input, ABS_MT_POSITION_X, xpos); + input_report_abs(byd_priv->input, ABS_MT_POSITION_Y, ypos); + input_report_abs(byd_priv->input, ABS_MT_WIDTH_MAJOR, REPORT_WIDTH_MAJOR); //Touch Size + + #ifdef CONFIG_TS_COORDIATE_DEBUG + printk(" Finger Touch X = %d , Y = %d, State = 0x%x,Finger_ID=0x%x\n\n",xpos,ypos,Finger_Status,Finger_ID); + #endif + } + + if (Finger_Status == 0xc0) + { + Report_Status = 1; + input_mt_slot(byd_priv->input, Finger_ID); + input_report_abs(byd_priv->input, ABS_MT_TRACKING_ID, -1); + #ifdef CONFIG_TS_COORDIATE_DEBUG + printk(" Touch release X = %d , Y = %d, State = 0x%x,Finger_ID=0x%x\n\n",xpos,ypos,Finger_Status,Finger_ID); + #endif + } + } + } + if (Report_Status) + { + input_sync(byd_priv->input); + } +} + +static int byd693x_init_platform_hw(void) +{ + if(gpio_request(byd6932_pdata->rst_pin,NULL) != 0){ + gpio_free(byd6932_pdata->rst_pin); + printk("byd693x_init_platform_hw gpio_request error\n"); + return -EIO; + } + + if(gpio_request(byd6932_pdata->int_pin, NULL) != 0){ + gpio_free(byd6932_pdata->int_pin); + printk("byd693x_init_platform_hw gpio_request error\n"); + return -EIO; + } + gpio_pull_updown(byd6932_pdata->int_pin, 1); + gpio_direction_output(byd6932_pdata->rst_pin, 1); + return 0; +} + + +static int byd693x_ts_probe(struct i2c_client *client,const struct i2c_device_id *idp) +{ + struct byd_ts_priv *byd_priv; + struct input_dev *byd_input = NULL; + struct byd_platform_data *pdata = client->dev.platform_data; + unsigned char tp_buf[1]; + int error = -1; + + + byd6932_pdata = client->dev.platform_data; + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_probe! |\n"); + printk("+-----------------------------------------+\n"); + #endif + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: need I2C_FUNC_I2C\n"); + #endif + return -ENODEV; + } + else + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: i2c Check OK!\n"); + printk(" byd693x_ts_probe: i2c_client name : %s\n",client->name); + #endif + } + + byd_priv = kzalloc(sizeof(*byd_priv), GFP_KERNEL); + if (!byd_priv) + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: kzalloc Error!\n"); + #endif + error=-ENODEV; + goto err0; + } + else + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: kzalloc OK!\n"); + #endif + } + + + + dev_set_drvdata(&client->dev, byd_priv); + byd_input = input_allocate_device(); + if (!byd_input) + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: input_allocate_device Error\n"); + #endif + error=-ENODEV; + goto err1; + } + else + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: input_allocate_device OK\n"); + #endif + } + + //only check BYD BF6932 + error = ReadRegister(client, BYD_COORD_READ_ADDR, tp_buf, sizeof(tp_buf)); + if (error <= 0) + { + printk(KERN_ALERT "BYD BF6932 Touchscreen not found \n"); + gpio_free(pdata->rst_pin); + gpio_free(pdata->int_pin); + goto err1; + } + +// byd_input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN)|BIT_MASK(EV_REP) ; +// byd_input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_2); + byd_input->name = client->name; + byd_input->id.bustype = BUS_I2C; + byd_input->id.vendor = 0x2878; // Modify for Vendor ID + byd_input->dev.parent = &client->dev; +// byd_input->open = byd693x_ts_open; +// byd_input->close = byd693x_ts_close; + input_set_drvdata(byd_input, byd_priv); + byd_priv->client = client; + byd_priv->input = byd_input; + byd_priv->irq = pdata->int_pin; + byd_priv->FingerNo=FINGER_NO_MAX; + + byd_input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + byd_input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); // for android + + __set_bit(EV_ABS, byd_input->evbit); + __set_bit(INPUT_PROP_DIRECT, byd_input->propbit); + set_bit(ABS_MT_POSITION_X, byd_input->absbit); + set_bit(ABS_MT_POSITION_Y, byd_input->absbit); + set_bit(ABS_MT_TOUCH_MAJOR, byd_input->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, byd_input->absbit); + +// deviceReset(client); +// printk("BYD Touchscreen I2C Address: 0x%02X\n",client->addr); +// printk("BYD Touchscreen Device ID : BF6932\n"); + + //config the resolution of CTP + byd693xcfg_Resolution[RESO_X_NO].Data1 = (char)(pdata->screen_max_x >>8); + byd693xcfg_Resolution[RESO_X_NO].Data2 = (char)(pdata->screen_max_x & 0xff); + + byd693xcfg_Resolution[RESO_Y_NO].Data1 = (char)(pdata->screen_max_y >>8); + byd693xcfg_Resolution[RESO_Y_NO].Data2 = (char)(pdata->screen_max_y & 0xff); + + byd693xdeviceInit(client); + + input_mt_init_slots(byd_input, MAX_TRACKID_ITEM); + + + input_set_abs_params(byd_input, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR, 0, 0); + input_set_abs_params(byd_input, ABS_MT_WIDTH_MAJOR, 0, MAX_WIDTH_MAJOR, 0, 0); + input_set_abs_params(byd_input, ABS_MT_POSITION_X, 0,pdata->screen_max_x + 1, 0, 0); + input_set_abs_params(byd_input, ABS_MT_POSITION_Y, 0,pdata->screen_max_y + 1, 0, 0); + +#ifdef USE_TOUCH_KEY + set_bit(KEY_MENU, byd_input->keybit); + set_bit(KEY_HOME, byd_input->keybit); + set_bit(KEY_BACK, byd_input->keybit); + set_bit(KEY_SEARCH, byd_input->keybit); +#endif + + INIT_WORK(&byd_priv->byd_work, byd693x_ts_work); + + error = input_register_device(byd_input); + + if(error) + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: input_register_device input Error!\n"); + #endif + error=-ENODEV; + goto err1; + } + else + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: input_register_device input OK!\n"); + #endif + } + + error = byd693x_init_platform_hw(); //Init RK29 GPIO + if(0 != error) + { + printk("%s:Init_INT set_irq_mode err. \n", __func__); + goto exit_set_irq_mode; + } + // Options for different interrupt system +// error = request_irq(byd_priv->irq, byd693x_ts_isr, IRQF_DISABLED|IRQF_TRIGGER_FALLING, client->name,byd_priv); +// error = request_irq(byd_priv->irq, byd693x_ts_isr, IRQF_TRIGGER_FALLING, client->name,byd_priv); + error = request_irq(byd_priv->irq, byd693x_ts_isr, IRQF_TRIGGER_FALLING, client->name,byd_priv); + if(error) + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: request_irq Error!\n"); + #endif + error=-ENODEV; + goto err2; + } + else + { + #ifdef CONFIG_TS_PROBE_DEBUG + printk(" byd693x_ts_probe: request_irq OK!\n"); + #endif + } + + printk("Install BYD BF6932 Touchscreen driver successfully\n"); + +#ifdef CONFIG_HAS_EARLYSUSPEND + byd_priv->early_suspend.suspend = byd693x_ts_early_suspend; + byd_priv->early_suspend.resume = byd693x_ts_late_resume; + byd_priv->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB+1; + register_early_suspend(&byd_priv->early_suspend); +#endif + return 0; +exit_set_irq_mode: +err2: input_unregister_device(byd_input); +err1: input_free_device(byd_input); + kfree(byd_priv); +//exit_gpio_wakeup_request_failed: +err0: dev_set_drvdata(&client->dev, NULL); + return error; +} + +/* +static int byd693x_ts_open(struct input_dev *dev) +{ + struct byd_ts_priv *byd_priv = input_get_drvdata(dev); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_open! |\n"); + printk("+-----------------------------------------+\n"); + #endif + deviceResume(byd_priv->client); + enable_irq(byd_priv->irq); + byd_priv->suspend_opend = 0; + return 0; +} + +static void byd693x_ts_close(struct input_dev *dev) +{ + struct byd_ts_priv *byd_priv = input_get_drvdata(dev); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_close! |\n"); + printk("+-----------------------------------------+\n"); + #endif + deviceSuspend(byd_priv->client); + byd_priv->suspend_opend = 1; + disable_irq(byd_priv->irq); +} +*/ + +static int byd693x_ts_resume(struct i2c_client *client) +{ + struct byd_ts_priv *byd_priv = dev_get_drvdata(&client->dev); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_resume! |\n"); + printk("+-----------------------------------------+\n"); + #endif + + deviceResume(client); + byd_priv->suspend_opend = 0; + enable_irq(byd_priv->irq); + return 0; +} + +static int byd693x_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct byd_ts_priv *byd_priv = dev_get_drvdata(&client->dev); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_suspend! |\n"); + printk("+-----------------------------------------+\n"); + #endif + byd_priv->suspend_opend = 1; + + disable_irq(byd_priv->irq); + deviceSuspend(client); + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void byd693x_ts_late_resume(struct early_suspend *h) +{ + struct byd_ts_priv *byd_priv = container_of(h, struct byd_ts_priv, early_suspend); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_late_resume! |\n"); + printk("+-----------------------------------------+\n"); + #endif + byd693x_ts_resume(byd_priv->client); +} +static void byd693x_ts_early_suspend(struct early_suspend *h) +{ + struct byd_ts_priv *byd_priv = container_of(h, struct byd_ts_priv, early_suspend); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_early_suspend! |\n"); + printk("+-----------------------------------------+\n"); + #endif + byd693x_ts_suspend(byd_priv->client, PMSG_SUSPEND); +} +#endif + +static int byd693x_ts_remove(struct i2c_client *client) +{ + struct byd_ts_priv *byd_priv = dev_get_drvdata(&client->dev); + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_remove ! |\n"); + printk("+-----------------------------------------+\n"); + #endif + free_irq(byd_priv->irq, byd_priv); + input_unregister_device(byd_priv->input); + input_free_device(byd_priv->input); + kfree(byd_priv); + dev_set_drvdata(&client->dev, NULL); + return 0; +} + +static irqreturn_t byd693x_ts_isr(int irq, void *dev_id) +{ + struct byd_ts_priv *byd_priv = dev_id; + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_isr! |\n"); + printk("+-----------------------------------------+\n"); + #endif + disable_irq_nosync(byd_priv->irq); + queue_work(byd693x_wq, &byd_priv->byd_work); + enable_irq(byd_priv->irq); + return IRQ_HANDLED; +} + +static const struct i2c_device_id byd693x_ts_id[] = { + { CTP_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, byd693x_ts_id); + +static struct i2c_driver byd693x_ts_driver = { + .driver = { + .name = CTP_NAME, + }, + .probe = byd693x_ts_probe, + .remove = byd693x_ts_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = byd693x_ts_suspend, + .resume = byd693x_ts_resume, +#endif + .id_table = byd693x_ts_id, +}; + +static char banner[] __initdata = KERN_INFO "BYD Touchscreen driver, (c) 2012 BYD Systech Ltd.\n"; +static int __init byd693x_ts_init(void) +{ + int ret; + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd_ts_init! |\n"); + printk("+-----------------------------------------+\n"); + #endif + printk(banner); + printk("==================byd693x_ts_init===========================\n"); + printk("Version =%s\n",VERSION); + byd693x_wq = create_singlethread_workqueue("byd693x_wq"); + if (!byd693x_wq) + { + #ifdef CONFIG_TS_WORKQUEUE_DEBUG + printk(" byd693x_ts_init: create_singlethread_workqueue Error!\n"); + #endif + return -ENOMEM; + } + else + { + #ifdef CONFIG_TS_WORKQUEUE_DEBUG + printk(" byd693x_ts_init: create_singlethread_workqueue OK!\n"); + #endif + } + ret=i2c_add_driver(&byd693x_ts_driver); + #ifdef CONFIG_TS_I2C_TRANSFER_DEBUG + if(ret) printk(" byd693x_ts_init: i2c_add_driver Error! \n"); + else printk(" byd693x_ts_init: i2c_add_driver OK! \n"); + #endif + return ret; +} + +static void __exit byd693x_ts_exit(void) +{ + #ifdef CONFIG_TS_FUNCTION_CALLED_DEBUG + printk("+-----------------------------------------+\n"); + printk("| byd693x_ts_exit! |\n"); + printk("+-----------------------------------------+\n"); + #endif + i2c_del_driver(&byd693x_ts_driver); + if (byd693x_wq) destroy_workqueue(byd693x_wq); +} + +module_init(byd693x_ts_init); +module_exit(byd693x_ts_exit); + +MODULE_AUTHOR("BYD Systech Ltd - Raysens Design Technology, Charles Chen."); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("byd693x Touchscreen Driver 1.2_Charles@Raysens@20120731"); diff --git a/drivers/input/touchscreen/byd693x_ts.h b/drivers/input/touchscreen/byd693x_ts.h new file mode 100644 index 000000000000..d176772c4155 --- /dev/null +++ b/drivers/input/touchscreen/byd693x_ts.h @@ -0,0 +1,43 @@ +//a4, 52 +#define MAX_TOUCH_MAJOR 10 //Charles added +#define MAX_WIDTH_MAJOR 15 //Charles added +#define MAX_TRACKID_ITEM 10 //Charles added + +#define REPORT_TOUCH_MAJOR 5 //Charles added +#define REPORT_WIDTH_MAJOR 8 //Charles added + +#define REPORT_TPKEY_DOWN 1 +#define REPORT_TPKEY_UP 0 + +//#define RK29xx_ANDROID2_3_REPORT //if the Android system is V2.3 +//#undef RK29xx_ANDROID2_3_REPORT +#define RK29xx_ANDROID4_0_REPORT //if the Android system is V4.0 +//#undef RK29xx_ANDROID4_0_REPORT + +//----------------------------------------// +//#define TOUCH_INT_PIN RK29_PINx_PAx //define INT Pin Should be changed to the INT GPIO Port and Pin +//#define TOUCH_RESET_PIN RK29_PINx_PAx //define Reset Pin Should be changed to the Reset GPIO Port and Pin +//#define SW_INT_IRQNO_PIO TOUCH_INT_PIN + +#define byd693x_I2C_RATE 100*1000 //400KHz + +#define USE_TOUCH_KEY + +#ifdef USE_TOUCH_KEY +static const uint32_t TPKey_code[4] ={ KEY_SEARCH,KEY_MENU,KEY_HOME,KEY_BACK }; +#endif + +//struct ChipSetting byd693xcfg_Table1[]={ +//{ 2,0x08, 200/256, 200%256}, // 1 FTHD_H;FTHD_L //ÊÖÖ¸°´¼üãÐÖµ +//{ 2,0x0A, 120/256, 120%256}, // 2 NTHD_H;NTHD_L //ÔëÉùãÐÖµ +//{ 2,0x0C, SCREEN_MAX_X/256, SCREEN_MAX_X%256}, // 3 RESX_H;RESX_L //X·Ö±æÂÊ +//{ 2,0x0E, SCREEN_MAX_Y/256, SCREEN_MAX_Y%256}, // 4 RESY_H;RESY_L //Y·Ö±æÂÊ +//}; + +static struct ChipSetting Resume[]={ +{ 1, 0x07, 0x01, 0x00}, // Wakeup TP from Sleep mode +}; + +static struct ChipSetting Suspend[] ={ +{ 1, 0x07, 0x00, 0x00}, // Enter Sleep mode +}; -- 2.34.1